Skip to content

Commit 5cf1173

Browse files
committed
Volume move: direct unit tests + write-cancelled fix
- Add `volume_move_tests.rs` driving `move_volumes_with_progress` (cross-volume) and `move_within_same_volume_with_progress` (same-volume) directly via `CollectorEventSink` + `InMemoryVolume`. 13 tests mirror the `volume_copy_tests.rs` patterns: happy path, conflict + Skip/Overwrite/Stop, pre-known-conflict bulk-skip (data-safety: closure never invoked for bulk-skipped sources), per-iter skip accounting, cross-volume cancel between sources, cancel mid-batch invariant (each path is at exactly one of source/dest, never both, never neither), and a real-FS smoke against `LocalPosixVolume`. - Fix latent bug: both inner functions returned `Err(Cancelled)` on cancel but never emitted `write-cancelled`. The outer wrapper's `Err(Cancelled)` arm only logs (to avoid double-emitting `write-error`), so the FE never saw the cancel and the progress dialog would stay open. Now mirrors `copy_volumes_with_progress`: emits a `WriteCancelledEvent` with `rolled_back: false` before returning. The CLAUDE.md "move_* inner handlers already emit write-cancelled" claim is now accurate. - M1 step 4 of the transfer-driver refactor (see `docs/specs/transfer-driver-refactor-plan.md`).
1 parent 1280056 commit 5cf1173

2 files changed

Lines changed: 781 additions & 3 deletions

File tree

apps/desktop/src-tauri/src/file_system/write_operations/volume_move.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use super::state::{
1616
WRITE_OPERATION_STATE, WriteOperationState, is_cancelled, register_operation_status, unregister_operation_status,
1717
};
1818
use super::types::{
19-
ConflictResolution, OperationEventSink, TauriEventSink, VolumeCopyConfig, WriteCompleteEvent, WriteErrorEvent,
20-
WriteOperationConfig, WriteOperationError, WriteOperationPhase, WriteOperationStartResult, WriteOperationType,
21-
WriteProgressEvent,
19+
ConflictResolution, OperationEventSink, TauriEventSink, VolumeCopyConfig, WriteCancelledEvent, WriteCompleteEvent,
20+
WriteErrorEvent, WriteOperationConfig, WriteOperationError, WriteOperationPhase, WriteOperationStartResult,
21+
WriteOperationType, WriteProgressEvent,
2222
};
2323
use super::volume_conflict::resolve_volume_conflict;
2424
use super::volume_copy::{WriteFailure, delete_volume_path_recursive, map_volume_error, write_error_event_from};
@@ -214,6 +214,18 @@ pub(super) async fn move_volumes_with_progress(
214214

215215
for source_path in source_paths {
216216
if is_cancelled(&state.intent) {
217+
// Move has no rollback (it's copy+delete-source per file); cancelling
218+
// leaves whatever's already at dest alone and stops further work. We
219+
// emit `write-cancelled` here so the FE sees the cancel for the move
220+
// path too, mirroring `copy_volumes_with_progress`. Without this, the
221+
// outer wrapper would only log the cancel and the dialog would never
222+
// close.
223+
events.emit_cancelled(WriteCancelledEvent {
224+
operation_id: operation_id.to_string(),
225+
operation_type: WriteOperationType::Move,
226+
files_processed: files_done,
227+
rolled_back: false,
228+
});
217229
return Err(WriteFailure::synthetic(WriteOperationError::Cancelled {
218230
message: "Operation cancelled by user".to_string(),
219231
}));
@@ -551,6 +563,15 @@ pub(super) async fn move_within_same_volume_with_progress(
551563

552564
for source_path in source_paths {
553565
if is_cancelled(&state.intent) {
566+
// Same-volume rename has no rollback (the previous renames stay
567+
// in place). Emit `write-cancelled` so the FE closes the dialog;
568+
// the outer wrapper only logs the typed `Cancelled` error.
569+
events.emit_cancelled(WriteCancelledEvent {
570+
operation_id: operation_id.to_string(),
571+
operation_type: WriteOperationType::Move,
572+
files_processed: files_moved,
573+
rolled_back: false,
574+
});
554575
return Err(WriteOperationError::Cancelled {
555576
message: "Operation cancelled by user".to_string(),
556577
});
@@ -676,3 +697,7 @@ pub(super) async fn move_within_same_volume_with_progress(
676697

677698
Ok(())
678699
}
700+
701+
#[cfg(test)]
702+
#[path = "volume_move_tests.rs"]
703+
mod tests;

0 commit comments

Comments
 (0)