use crate::{
CreateFile, CreateSymlink, DeleteNode, DeleteNodePreimage, NodeId, NodeKind, ObjectId,
RenamePath,
};
const NODE_ID: NodeId = NodeId::from_bytes([0x30; 32]);
const BLOB_ID: ObjectId = ObjectId::from_bytes([0x40; 32]);
const VALID_PATHS: [&str; 1] = ["a/b.txt"];
const INVALID_PATHS: [(&str, &str); 4] = [
("com1", "Windows-reserved device name"),
("../escape", "traversal component"),
("/absolute", "absolute path"),
(".prikk/FORMAT", ".prikk-prefixed path"),
];
fn create_file(path: &str) -> CreateFile {
CreateFile {
path: path.to_string(),
node_id: NODE_ID,
blob_id: BLOB_ID,
mode: 0o100_644,
}
}
fn delete_node(path: &str) -> DeleteNode {
DeleteNode {
path: path.to_string(),
node_id: NODE_ID,
old_node_kind: NodeKind::TextFile,
preimage: DeleteNodePreimage::File {
old_blob_id: BLOB_ID,
old_mode: 0o100_644,
},
}
}
fn rename_path(old_path: &str, new_path: &str) -> RenamePath {
RenamePath {
node_id: NODE_ID,
old_path: old_path.to_string(),
new_path: new_path.to_string(),
}
}
fn create_symlink(path: &str) -> CreateSymlink {
CreateSymlink {
path: path.to_string(),
node_id: NODE_ID,
target: "somewhere".to_string(),
}
}
#[test]
fn valid_paths_encode_successfully_for_every_kind() {
for path in VALID_PATHS {
assert!(create_file(path).validate().is_ok(), "CreateFile {path}");
assert!(delete_node(path).validate().is_ok(), "DeleteNode {path}");
assert!(
rename_path(path, path).validate().is_ok(),
"RenamePath {path}"
);
assert!(
create_symlink(path).validate().is_ok(),
"CreateSymlink {path}"
);
}
}
#[test]
fn invalid_paths_fail_at_encode_for_every_kind() {
for (path, reason) in INVALID_PATHS {
assert!(
create_file(path).validate().is_err(),
"CreateFile should reject {path} ({reason})"
);
assert!(
delete_node(path).validate().is_err(),
"DeleteNode should reject {path} ({reason})"
);
assert!(
rename_path("a", path).validate().is_err(),
"RenamePath.new_path should reject {path} ({reason})"
);
assert!(
create_symlink(path).validate().is_err(),
"CreateSymlink should reject {path} ({reason})"
);
}
}
#[test]
fn rename_path_rejects_a_bad_old_path_even_when_new_path_is_valid() {
let op = rename_path("com1", "valid");
assert!(
op.validate().is_err(),
"old_path=\"com1\" must be rejected even though new_path is valid"
);
}
#[test]
fn opaque_target_fields_still_accept_arbitrary_utf8() {
let delete_symlink = DeleteNode {
path: "a".to_string(),
node_id: NODE_ID,
old_node_kind: NodeKind::Symlink,
preimage: DeleteNodePreimage::Symlink {
old_target: "com1".to_string(), },
};
assert!(delete_symlink.validate().is_ok());
let symlink = CreateSymlink {
path: "a".to_string(),
node_id: NODE_ID,
target: "../anywhere".to_string(), };
assert!(symlink.validate().is_ok());
}