- 1001
) - 1002
.await; - 1003
assert!(!revised.is_error, "{}", revised.content); - 1004
assert!( - 1005
!body(&revised).contains(r#"w:author="mira""#), - 1006
"a revision's copy of a new document stays clean, though the copy holds the file" - 1007
); - 1008
} - 1009
- 1010
#[tokio::test] - 1011
async fn refuses_escapes_bad_ops_and_failed_edits_without_writing() { - 1012
let dir = tempfile::tempdir().unwrap(); - 1013
let file = dir.path().join("memo.docx"); - 1014
std::fs::write(&file, vak_ooxml::fixtures::docx()).unwrap(); - 1015
let digest = digest_of(&file); - 1016
for (args, expected) in [ - 1017
( - 1018
serde_json::json!({"path": "../x.docx", "source": "memo.docx", "base_digest": digest, "ops": []}), - 1019
"outside the workspace", - 1020
), - 1021
( - 1022
serde_json::json!({"path": "memo.docx", "base_digest": digest, "ops": [{"op": "replace_paragraph_text", "anchor": "p@11", "txt": "x"}]}), - 1023
"ops are not valid", - 1024
), - 1025
( - 1026
serde_json::json!({"path": "memo.docx", "base_digest": digest, "ops": [{"op": "delete_paragraph", "anchor": "p@11"}]}), - 1027
"nothing was written: op 1", - 1028
), - 1029
( - 1030
serde_json::json!({"path": "memo.docm", "source": "memo.docx", "base_digest": digest, "ops": []}), - 1031
"never turns a file macro-enabled", - 1032
), - 1033
( - 1034
serde_json::json!({"path": "memo.txt", "source": "memo.docx", "base_digest": digest, "ops": []}), - 1035
"not named as a Word", - 1036
), - 1037
] { - 1038
let output = run(dir.path(), args).await; - 1039
assert!(output.is_error, "{}", output.content); - 1040
assert!(output.content.contains(expected), "{}", output.content); - 1041
} - 1042
assert_eq!(std::fs::read(&file).unwrap(), vak_ooxml::fixtures::docx()); - 1043
let leftovers: Vec<_> = std::fs::read_dir(dir.path()).unwrap().collect(); - 1044
assert_eq!( - 1045
leftovers.len(), - 1046
1, - 1047
"no draft and no temporary file are left behind" - 1048
); - 1049
} - 1050
- 1051
#[tokio::test] - 1052
async fn a_new_file_is_created_from_scratch_as_a_draft() { - 1053
let dir = tempfile::tempdir().unwrap(); - 1054
let created = run( - 1055
dir.path(), - 1056
serde_json::json!({ - 1057
"path": "memo.docx", - 1058
"ops": [ - 1059
{"op": "add_paragraph", "text": "Q3 review", "style": "Title"}, - 1060
{"op": "add_paragraph", "text": "Revenue grew 12%."}, - 1061
{"op": "add_table", "rows": [["Region", "Revenue"], ["North", 120]]} - 1062
] - 1063
}), - 1064
) - 1065
.await; - 1066
assert!(!created.is_error, "{}", created.content); - 1067
assert!( - 1068
created.content.contains("memo.docx is a new file, not in the workspace until a person reviews and accepts the draft"), - 1069
"{}", - 1070
created.content - 1071
); - 1072
assert!( - 1073
created - 1074
.content - 1075
.contains("It is a new file: 2 paragraphs, 9 words, 1 heading, 1 table."), - 1076
"{}", - 1077
created.content - 1078
); - 1079
assert!( - 1080
!created.content.contains("tracked changes by"), - 1081
"{}", - 1082
created.content - 1083
); - 1084
assert!( - 1085
!dir.path().join("memo.docx").exists(), - 1086
"only a draft is written" - 1087
); - 1088
let draft = dir.path().join(draft_path(&created)); - 1089
assert!(draft.starts_with(dir.path().join(".vak/scratch/mira"))); - 1090
let document = vak_ooxml::read::read( - 1091
std::io::Cursor::new(std::fs::read(&draft).unwrap()), - 1092
vak_ooxml::Limits::default(), - 1093
) - 1094
.unwrap(); - 1095
let lines = document.lines().join("\n"); - 1096
assert!(lines.contains("# Q3 review"), "{lines}"); - 1097
assert!( - 1098
lines.contains("[tbl@1/r2] [p:1A000005] North | [p:1A000006] 120"), - 1099
"{lines}" - 1100
); - 1101
- 1102
for extension in ["xlsx", "pptx", "dotx"] { - 1103
let op = match extension { - 1104
"xlsx" => { - 1105
serde_json::json!({"op": "set_cells", "sheet": "Sheet1", "cells": {"A1": "Item"}}) - 1106
} - 1107
"pptx" => { - 1108
serde_json::json!({"op": "add_slide_from_layout", "layout": "Title Slide", "placeholders": {"title": "Launch"}}) - 1109
} - 1110
_ => serde_json::json!({"op": "add_paragraph", "text": "Letterhead"}), - 1111
}; - 1112
let output = run( - 1113
dir.path(), - 1114
serde_json::json!({"path": format!("new.{extension}"), "ops": [op]}), - 1115
) - 1116
.await; - 1117
assert!(!output.is_error, "{extension}: {}", output.content); - 1118
} - 1119
} - 1120
- 1121
#[tokio::test] - 1122
async fn creating_is_refused_where_it_would_hide_a_mistake() { - 1123
let dir = tempfile::tempdir().unwrap(); - 1124
std::fs::write(dir.path().join("brand.docx"), vak_ooxml::fixtures::docx()).unwrap(); - 1125
let add = serde_json::json!([{"op": "add_paragraph", "text": "x"}]); - 1126
let refusal = |output: &ToolOutput, needle: &str| { - 1127
assert!(output.is_error, "{}", output.content); - 1128
assert!(output.content.contains(needle), "{}", output.content); - 1129
}; - 1130
refusal( - 1131
&run( - 1132
dir.path(), - 1133
serde_json::json!({"path": "brand.docx", "ops": add}), - 1134
) - 1135
.await, - 1136
"brand.docx already exists", - 1137
); - 1138
refusal( - 1139
&run( - 1140
dir.path(), - 1141
serde_json::json!({"path": "brnad.docx", "base_digest": "0123456789abcdef", "ops": add}), - 1142
) - 1143
.await, - 1144
"brnad.docx does not exist, so there is no file for base_digest to name", - 1145
); - 1146
refusal( - 1147
&run( - 1148
dir.path(), - 1149
serde_json::json!({"path": "memo.docx", "source": "brand.docx", "ops": add}), - 1150
) - 1151
.await, - 1152
"missing base_digest for source brand.docx", - 1153
); - 1154
refusal( - 1155
&run( - 1156
dir.path(), - 1157
serde_json::json!({"path": "memo.docm", "ops": add}), - 1158
) - 1159
.await, - 1160
"never makes a macro-enabled file", - 1161
); - 1162
refusal( - 1163
&run( - 1164
dir.path(), - 1165
serde_json::json!({"path": "flow.vsdx", "ops": add}), - 1166
) - 1167
.await, - 1168
"Visio drawing cannot be created from scratch yet", - 1169
); - 1170
refusal( - 1171
&run( - 1172
dir.path(), - 1173
serde_json::json!({"path": "memo.docx", "ops": [{"op": "set_cells", "sheet": "Sheet1", "cells": {"A1": 1}}]}), - 1174
) - 1175
.await, - 1176
"this op edits an Excel workbook", - 1177
); - 1178
let scratch = dir.path().join(".vak"); - 1179
assert!( - 1180
!scratch.exists() - 1181
|| std::fs::read_dir(scratch.join("scratch/mira")) - 1182
.map(|entries| entries.count()) - 1183
.unwrap_or(0) - 1184
== 0, - 1185
"a refused creation writes no draft" - 1186
); - 1187
} - 1188
} - 1189
Indexing the workspace…
Vakyartha documentation is discovering safe artifacts, anchors, and source references.