diff --git a/src/backend/Windows.zig b/src/backend/Windows.zig index ed0a40b..d4dacd2 100644 --- a/src/backend/Windows.zig +++ b/src/backend/Windows.zig @@ -253,12 +253,6 @@ fn thread_fn( } gop.value_ptr.* = ot; } - // A directory that appears via move-in carries existing children - // that will never generate FILE_ACTION_ADDED events. Scan its - // contents into the cache so subsequent deletes resolve their - // type. Scanning a genuinely new (empty) directory is a no-op. - if (ot == .dir and event_type == .created) - scan_path_types_into(allocator, path_types, full_path); break :blk ot; }; // Suppress FILE_ACTION_MODIFIED on directories: these are diff --git a/src/nightwatch_test.zig b/src/nightwatch_test.zig index d2e83dd..e94e7af 100644 --- a/src/nightwatch_test.zig +++ b/src/nightwatch_test.zig @@ -643,146 +643,6 @@ fn testRenameThenModify(comptime Watcher: type, allocator: std.mem.Allocator) !v try std.testing.expect(rename_idx < modify_idx); } -fn testMoveOutFile(comptime Watcher: type, allocator: std.mem.Allocator) !void { - const TH = MakeTestHandler(Watcher); - - const watched = try makeTempDir(allocator); - defer { - removeTempDir(watched); - allocator.free(watched); - } - const other = try makeTempDir(allocator); - defer { - removeTempDir(other); - allocator.free(other); - } - - const th = try TH.init(allocator); - defer th.deinit(); - - var watcher = try Watcher.init(allocator, &th.handler); - defer watcher.deinit(); - try watcher.watch(watched); - - const src_path = try std.fs.path.join(allocator, &.{ watched, "moveme.txt" }); - defer allocator.free(src_path); - const dst_path = try std.fs.path.join(allocator, &.{ other, "moveme.txt" }); - defer allocator.free(dst_path); - - { - const f = try std.fs.createFileAbsolute(src_path, .{}); - f.close(); - } - try drainEvents(Watcher, &watcher); - - try std.fs.renameAbsolute(src_path, dst_path); - try drainEvents(Watcher, &watcher); - - // File moved out of the watched tree: appears as deleted (INotify, Windows) - // or renamed (kqueue, which holds a vnode fd and sees NOTE_RENAME). - const src_gone = th.hasChange(src_path, .deleted, .file) or - th.hasChange(src_path, .renamed, .file); - try std.testing.expect(src_gone); - // No event for the destination - it is in an unwatched directory. - try std.testing.expect(!th.hasChange(dst_path, .created, .file)); -} - -fn testMoveInFile(comptime Watcher: type, allocator: std.mem.Allocator) !void { - const TH = MakeTestHandler(Watcher); - - const watched = try makeTempDir(allocator); - defer { - removeTempDir(watched); - allocator.free(watched); - } - const other = try makeTempDir(allocator); - defer { - removeTempDir(other); - allocator.free(other); - } - - const th = try TH.init(allocator); - defer th.deinit(); - - var watcher = try Watcher.init(allocator, &th.handler); - defer watcher.deinit(); - try watcher.watch(watched); - - const src_path = try std.fs.path.join(allocator, &.{ other, "moveme.txt" }); - defer allocator.free(src_path); - const dst_path = try std.fs.path.join(allocator, &.{ watched, "moveme.txt" }); - defer allocator.free(dst_path); - - { - const f = try std.fs.createFileAbsolute(src_path, .{}); - f.close(); - } - - try std.fs.renameAbsolute(src_path, dst_path); - try drainEvents(Watcher, &watcher); - - // File moved into the watched tree: appears as created. - try std.testing.expect(th.hasChange(dst_path, .created, .file)); - // No event for the source - it was in an unwatched directory. - try std.testing.expect(!th.hasChange(src_path, .deleted, .file)); -} - -fn testMoveInSubdir(comptime Watcher: type, allocator: std.mem.Allocator) !void { - const TH = MakeTestHandler(Watcher); - - const watched = try makeTempDir(allocator); - defer { - removeTempDir(watched); - allocator.free(watched); - } - const other = try makeTempDir(allocator); - defer { - removeTempDir(other); - allocator.free(other); - } - - const th = try TH.init(allocator); - defer th.deinit(); - - var watcher = try Watcher.init(allocator, &th.handler); - defer watcher.deinit(); - try watcher.watch(watched); - - const src_sub = try std.fs.path.join(allocator, &.{ other, "sub" }); - defer allocator.free(src_sub); - const dst_sub = try std.fs.path.join(allocator, &.{ watched, "sub" }); - defer allocator.free(dst_sub); - const src_file = try std.fs.path.join(allocator, &.{ src_sub, "f.txt" }); - defer allocator.free(src_file); - const dst_file = try std.fs.path.join(allocator, &.{ dst_sub, "f.txt" }); - defer allocator.free(dst_file); - - // Create subdir with a file in the unwatched root, then move it in. - try std.fs.makeDirAbsolute(src_sub); - { - const f = try std.fs.createFileAbsolute(src_file, .{}); - f.close(); - } - try std.fs.renameAbsolute(src_sub, dst_sub); - try drainEvents(Watcher, &watcher); - - try std.testing.expect(th.hasChange(dst_sub, .created, .dir)); - - // Delete the file inside the moved-in subdir. - try std.fs.deleteFileAbsolute(dst_file); - try drainEvents(Watcher, &watcher); - - // Object type must be .file, not .unknown - backend must have seeded - // the path_types cache when the subdir was moved in. - try std.testing.expect(th.hasChange(dst_file, .deleted, .file)); - - // Delete the now-empty subdir. - try std.fs.deleteDirAbsolute(dst_sub); - try drainEvents(Watcher, &watcher); - - try std.testing.expect(th.hasChange(dst_sub, .deleted, .dir)); -} - // --------------------------------------------------------------------------- // Test blocks - each runs its case across all available variants. // --------------------------------------------------------------------------- @@ -864,21 +724,3 @@ test "rename-then-modify: rename event precedes the subsequent modify event" { try testRenameThenModify(nw.Create(variant), std.testing.allocator); } } - -test "moving a file out of the watched tree appears as deleted or renamed" { - inline for (comptime std.enums.values(nw.Variant)) |variant| { - try testMoveOutFile(nw.Create(variant), std.testing.allocator); - } -} - -test "moving a file into the watched tree appears as created" { - inline for (comptime std.enums.values(nw.Variant)) |variant| { - try testMoveInFile(nw.Create(variant), std.testing.allocator); - } -} - -test "moving a subdir into the watched tree: contents can be deleted with correct types" { - inline for (comptime std.enums.values(nw.Variant)) |variant| { - try testMoveInSubdir(nw.Create(variant), std.testing.allocator); - } -} diff --git a/test_manual.ps1 b/test_manual.ps1 index 8e8ced7..672bc6b 100644 --- a/test_manual.ps1 +++ b/test_manual.ps1 @@ -14,14 +14,12 @@ if (-not (Test-Path $NW)) { exit 1 } -$TESTDIR = Join-Path $env:TEMP "nightwatch_manual_$PID" -$TESTDIR2 = Join-Path $env:TEMP "nightwatch_manual2_$PID" -$UNWATCHED = Join-Path $env:TEMP "nightwatch_unwatched_$PID" -New-Item -ItemType Directory -Path $TESTDIR | Out-Null -New-Item -ItemType Directory -Path $TESTDIR2 | Out-Null -New-Item -ItemType Directory -Path $UNWATCHED | Out-Null +$TESTDIR = Join-Path $env:TEMP "nightwatch_manual_$PID" +$TESTDIR2 = Join-Path $env:TEMP "nightwatch_manual2_$PID" +New-Item -ItemType Directory -Path $TESTDIR | Out-Null +New-Item -ItemType Directory -Path $TESTDIR2 | Out-Null -Write-Host "--- watching $TESTDIR and $TESTDIR2 (unwatched: $UNWATCHED) ---" +Write-Host "--- watching $TESTDIR and $TESTDIR2 ---" Write-Host "--- starting nightwatch (Ctrl-C to stop early) ---" Write-Host "" @@ -106,47 +104,9 @@ Write-Host "[op] rename subA: dir1 -> dir2 (subdir across roots)" Move-Item -Path "$TESTDIR\subA" -Destination "$TESTDIR2\subA2" Start-Sleep -Milliseconds 500 -Write-Host "" -Write-Host "# move in/out (one side unwatched)" -Write-Host "" - -Write-Host "[op] touch outfile.txt in dir1" -New-Item -ItemType File -Path "$TESTDIR\outfile.txt" | Out-Null -Start-Sleep -Milliseconds 400 - -Write-Host "[op] move outfile.txt: dir1 -> unwatched (move out)" -Move-Item -Path "$TESTDIR\outfile.txt" -Destination "$UNWATCHED\outfile.txt" -Start-Sleep -Milliseconds 400 - -Write-Host "[op] move outfile.txt: unwatched -> dir1 (move in)" -Move-Item -Path "$UNWATCHED\outfile.txt" -Destination "$TESTDIR\outfile.txt" -Start-Sleep -Milliseconds 400 - -Write-Host "[op] delete outfile.txt" -Remove-Item -Path "$TESTDIR\outfile.txt" -Start-Sleep -Milliseconds 400 - -Write-Host "[op] mkdir unwatched\subdir with a file" -New-Item -ItemType Directory -Path "$UNWATCHED\subdir" | Out-Null -New-Item -ItemType File -Path "$UNWATCHED\subdir\inside.txt" | Out-Null -Start-Sleep -Milliseconds 400 - -Write-Host "[op] move unwatched\subdir -> dir1\subdir (move subdir in)" -Move-Item -Path "$UNWATCHED\subdir" -Destination "$TESTDIR\subdir" -Start-Sleep -Milliseconds 400 - -Write-Host "[op] delete dir1\subdir\inside.txt" -Remove-Item -Path "$TESTDIR\subdir\inside.txt" -Start-Sleep -Milliseconds 400 - -Write-Host "[op] rmdir dir1\subdir" -Remove-Item -Path "$TESTDIR\subdir" -Start-Sleep -Milliseconds 500 - Write-Host "" Write-Host "--- done, stopping nightwatch ---" Stop-Process -Id $proc.Id -ErrorAction SilentlyContinue $proc.WaitForExit() Remove-Item -Recurse -Force -Path $TESTDIR Remove-Item -Recurse -Force -Path $TESTDIR2 -Remove-Item -Recurse -Force -Path $UNWATCHED diff --git a/test_manual.sh b/test_manual.sh index de90ef8..3680d14 100755 --- a/test_manual.sh +++ b/test_manual.sh @@ -15,8 +15,7 @@ fi TESTDIR=$(mktemp -d) TESTDIR2=$(mktemp -d) -UNWATCHED=$(mktemp -d) -echo "--- watching $TESTDIR and $TESTDIR2 (unwatched: $UNWATCHED) ---" +echo "--- watching $TESTDIR and $TESTDIR2 ---" echo "--- starting nightwatch (Ctrl-C to stop early) ---" echo "" @@ -102,45 +101,8 @@ echo "[op] rename subA: dir1 -> dir2 (subdir across roots)" mv "$TESTDIR/subA" "$TESTDIR2/subA2" sleep 0.5 -echo "" -echo "# move in/out (one side unwatched)" -echo "" - -echo "[op] touch outfile.txt in dir1" -touch "$TESTDIR/outfile.txt" -sleep 0.4 - -echo "[op] move outfile.txt: dir1 -> unwatched (move out)" -mv "$TESTDIR/outfile.txt" "$UNWATCHED/outfile.txt" -sleep 0.4 - -echo "[op] move outfile.txt: unwatched -> dir1 (move in)" -mv "$UNWATCHED/outfile.txt" "$TESTDIR/outfile.txt" -sleep 0.4 - -echo "[op] delete outfile.txt" -rm "$TESTDIR/outfile.txt" -sleep 0.4 - -echo "[op] mkdir unwatched/subdir with a file" -mkdir "$UNWATCHED/subdir" -touch "$UNWATCHED/subdir/inside.txt" -sleep 0.4 - -echo "[op] move unwatched/subdir -> dir1/subdir (move subdir in)" -mv "$UNWATCHED/subdir" "$TESTDIR/subdir" -sleep 0.4 - -echo "[op] delete dir1/subdir/inside.txt" -rm "$TESTDIR/subdir/inside.txt" -sleep 0.4 - -echo "[op] rmdir dir1/subdir" -rmdir "$TESTDIR/subdir" -sleep 0.5 - echo "" echo "--- done, stopping nightwatch ---" kill $NW_PID 2>/dev/null wait $NW_PID 2>/dev/null -rm -rf "$TESTDIR" "$TESTDIR2" "$UNWATCHED" +rm -rf "$TESTDIR" "$TESTDIR2"