177 lines
6.3 KiB
Rust
177 lines
6.3 KiB
Rust
use super::*;
|
|
use crate::proto::{
|
|
delete_file_response, discard_files_response, save_buffer_response, server_message,
|
|
write_file_response, DeleteFileResponse, DeleteFileSuccess, DiscardFilesError,
|
|
DiscardFilesResponse, DiscardFilesSuccess, FileOperationError, SaveBufferResponse,
|
|
SaveBufferSuccess, ServerMessage, WriteFileResponse, WriteFileSuccess,
|
|
};
|
|
|
|
fn msg(inner: server_message::Message) -> ServerMessage {
|
|
ServerMessage {
|
|
request_id: "req-1".to_string(),
|
|
message: Some(inner),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn write_file_success_is_ok_empty_is_err() {
|
|
let success = msg(server_message::Message::WriteFileResponse(
|
|
WriteFileResponse {
|
|
result: Some(write_file_response::Result::Success(WriteFileSuccess {})),
|
|
},
|
|
));
|
|
assert!(write_file_result(&success).is_ok());
|
|
|
|
let empty = msg(server_message::Message::WriteFileResponse(
|
|
WriteFileResponse { result: None },
|
|
));
|
|
assert!(write_file_result(&empty).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn write_file_error_propagates_message() {
|
|
let err = msg(server_message::Message::WriteFileResponse(
|
|
WriteFileResponse {
|
|
result: Some(write_file_response::Result::Error(FileOperationError {
|
|
message: "disk full".to_string(),
|
|
})),
|
|
},
|
|
));
|
|
assert_eq!(write_file_result(&err).unwrap_err(), "disk full");
|
|
}
|
|
|
|
#[test]
|
|
fn write_file_wrong_variant_is_err() {
|
|
let wrong = msg(server_message::Message::SaveBufferResponse(
|
|
SaveBufferResponse {
|
|
result: Some(save_buffer_response::Result::Success(SaveBufferSuccess {})),
|
|
},
|
|
));
|
|
assert!(write_file_result(&wrong).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn save_buffer_success_is_ok_empty_is_err() {
|
|
let success = msg(server_message::Message::SaveBufferResponse(
|
|
SaveBufferResponse {
|
|
result: Some(save_buffer_response::Result::Success(SaveBufferSuccess {})),
|
|
},
|
|
));
|
|
assert!(save_buffer_result(&success).is_ok());
|
|
|
|
let empty = msg(server_message::Message::SaveBufferResponse(
|
|
SaveBufferResponse { result: None },
|
|
));
|
|
assert!(save_buffer_result(&empty).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn save_buffer_error_propagates_message() {
|
|
let err = msg(server_message::Message::SaveBufferResponse(
|
|
SaveBufferResponse {
|
|
result: Some(save_buffer_response::Result::Error(FileOperationError {
|
|
message: "permission denied".to_string(),
|
|
})),
|
|
},
|
|
));
|
|
assert_eq!(save_buffer_result(&err).unwrap_err(), "permission denied");
|
|
}
|
|
|
|
#[test]
|
|
fn delete_file_success_is_ok_empty_is_err() {
|
|
let success = msg(server_message::Message::DeleteFileResponse(
|
|
DeleteFileResponse {
|
|
result: Some(delete_file_response::Result::Success(DeleteFileSuccess {})),
|
|
},
|
|
));
|
|
assert!(delete_file_result(&success).is_ok());
|
|
|
|
let empty = msg(server_message::Message::DeleteFileResponse(
|
|
DeleteFileResponse { result: None },
|
|
));
|
|
assert!(delete_file_result(&empty).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn delete_file_error_propagates_message() {
|
|
let err = msg(server_message::Message::DeleteFileResponse(
|
|
DeleteFileResponse {
|
|
result: Some(delete_file_response::Result::Error(FileOperationError {
|
|
message: "no such file".to_string(),
|
|
})),
|
|
},
|
|
));
|
|
assert_eq!(delete_file_result(&err).unwrap_err(), "no such file");
|
|
}
|
|
|
|
#[test]
|
|
fn discard_files_success_is_ok() {
|
|
let success = msg(server_message::Message::DiscardFilesResponse(
|
|
DiscardFilesResponse {
|
|
result: Some(discard_files_response::Result::Success(
|
|
DiscardFilesSuccess {},
|
|
)),
|
|
},
|
|
));
|
|
assert!(discard_files_result(&success).is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn discard_files_error_propagates_message() {
|
|
let err = msg(server_message::Message::DiscardFilesResponse(
|
|
DiscardFilesResponse {
|
|
result: Some(discard_files_response::Result::Error(DiscardFilesError {
|
|
message: "merge conflict".to_string(),
|
|
})),
|
|
},
|
|
));
|
|
assert_eq!(discard_files_result(&err).unwrap_err(), "merge conflict");
|
|
}
|
|
|
|
#[test]
|
|
fn discard_files_empty_result_is_err() {
|
|
let empty = msg(server_message::Message::DiscardFilesResponse(
|
|
DiscardFilesResponse { result: None },
|
|
));
|
|
assert!(discard_files_result(&empty).is_err());
|
|
}
|
|
|
|
/// Guard: every host-scoped request variant must have an explicit, intentional
|
|
/// response disposition. This match is exhaustive, so adding a new
|
|
/// `host_scoped_request::Message` variant fails to compile until it is
|
|
/// classified here — a prompt to add a `host_response` parser (or document why
|
|
/// the response is parsed at the manager call site).
|
|
#[test]
|
|
fn every_host_scoped_request_has_a_response_disposition() {
|
|
use crate::proto::host_scoped_request::Message as M;
|
|
|
|
fn disposition(m: &M) -> &'static str {
|
|
match m {
|
|
// Parsed via the helpers in this module.
|
|
M::WriteFile(_) => "host_response::write_file_result",
|
|
M::SaveBuffer(_) => "host_response::save_buffer_result",
|
|
M::DeleteFile(_) => "host_response::delete_file_result",
|
|
M::DiscardFiles(_) => "host_response::discard_files_result",
|
|
// Richer responses parsed at the manager call site.
|
|
M::ReadFileContext(_) => "manager::read_file_context",
|
|
M::GetFragmentMetadataFromHash(_) => "manager::get_fragment_metadata_from_hash",
|
|
M::UploadHandoffSnapshot(_) => "manager::upload_handoff_snapshot",
|
|
M::GetBranches(_) => "manager::get_branches",
|
|
M::IndexCodebase(_) => "manager::index_codebase",
|
|
M::DropCodebaseIndex(_) => "manager::drop_codebase_index",
|
|
M::ResyncCodebase(_) => "manager::resync_codebase",
|
|
M::ResolveConflict(_) => "manager::resolve_conflict",
|
|
M::GitCommitChain(_) => "manager::commit_chain",
|
|
M::GitPush(_) => "manager::push",
|
|
M::GitCreatePr(_) => "manager::create_pr",
|
|
M::GitGenerateCommitMessage(_) => "manager::generate_commit_message",
|
|
M::GitGetCommittedBranchFiles(_) => "manager::get_committed_branch_files",
|
|
M::RipgrepSearch(_) => "manager::start_ripgrep_search",
|
|
M::BackgroundJob(_) => "manager::HostRequestHandle::background_job",
|
|
}
|
|
}
|
|
|
|
// Referenced so the exhaustive match is compiled and checked.
|
|
let _ = disposition;
|
|
}
|