Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 168 additions & 0 deletions pkgs/watcher/test/file_watcher/link_tests.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:test/test.dart';

import '../utils.dart';

void linkTests({required bool isNative}) {
setUp(() async {
writeFile('target.txt');
writeLink(link: 'link.txt', target: 'target.txt');
});

test("doesn't notify if nothing is modified", () async {
await startWatcher(path: 'link.txt');
await expectNoEvents();
});

test('notifies when a link is overwritten with an identical file', () async {
await startWatcher(path: 'link.txt');
writeFile('link.txt');
await expectModifyEvent('link.txt');
});

test('notifies when a link is overwritten with a different file', () async {
await startWatcher(path: 'link.txt');
writeFile('link.txt', contents: 'modified');
await expectModifyEvent('link.txt');
});

test(
'notifies when a link target is overwritten with an identical file',
() async {
await startWatcher(path: 'link.txt');
writeFile('target.txt');

// TODO(davidmorgan): reconcile differences.
if (isNative) {
await expectModifyEvent('link.txt');
} else {
await expectNoEvents();
}
},
);

test('notifies when a link target is modified', () async {
await startWatcher(path: 'link.txt');
writeFile('target.txt', contents: 'modified');

// TODO(davidmorgan): reconcile differences.
if (isNative) {
await expectModifyEvent('link.txt');
} else {
await expectNoEvents();
}
});

test('notifies when a link is removed', () async {
await startWatcher(path: 'link.txt');
deleteFile('link.txt');

// TODO(davidmorgan): reconcile differences.
if (isNative) {
await expectNoEvents();
} else {
await expectRemoveEvent('link.txt');
}
});

test('notifies when a link target is removed', () async {
await startWatcher(path: 'link.txt');
deleteFile('target.txt');
await expectRemoveEvent('link.txt');
});

test('notifies when a link target is modified multiple times', () async {
await startWatcher(path: 'link.txt');

writeFile('target.txt', contents: 'modified');

// TODO(davidmorgan): reconcile differences.
if (isNative) {
await expectModifyEvent('link.txt');
} else {
await expectNoEvents();
}

writeFile('target.txt', contents: 'modified again');

// TODO(davidmorgan): reconcile differences.
if (isNative) {
await expectModifyEvent('link.txt');
} else {
await expectNoEvents();
}
});

test('notifies when a link is moved away', () async {
await startWatcher(path: 'link.txt');
renameFile('link.txt', 'new.txt');

// TODO(davidmorgan): reconcile differences.
if (isNative) {
await expectNoEvents();
} else {
await expectRemoveEvent('link.txt');
}
});

test('notifies when a link target is moved away', () async {
await startWatcher(path: 'link.txt');
renameFile('target.txt', 'new.txt');
await expectRemoveEvent('link.txt');
});

test('notifies when an identical file is moved over the link', () async {
await startWatcher(path: 'link.txt');
writeFile('old.txt');
renameFile('old.txt', 'link.txt');

// TODO(davidmorgan): reconcile differences.
if (isNative) {
await expectNoEvents();
} else {
await expectModifyEvent('link.txt');
}
});

test('notifies when an different file is moved over the link', () async {
await startWatcher(path: 'link.txt');
writeFile('old.txt', contents: 'modified');
renameFile('old.txt', 'link.txt');

// TODO(davidmorgan): reconcile differences.
if (isNative) {
await expectNoEvents();
} else {
await expectModifyEvent('link.txt');
}
});

test('notifies when an identical file is moved over the target', () async {
await startWatcher(path: 'link.txt');
writeFile('old.txt');
renameFile('old.txt', 'target.txt');

// TODO(davidmorgan): reconcile differences.
if (isNative) {
await expectModifyEvent('link.txt');
} else {
await expectNoEvents();
}
});

test('notifies when a different file is moved over the target', () async {
await startWatcher(path: 'link.txt');
writeFile('old.txt', contents: 'modified');
renameFile('old.txt', 'target.txt');

// TODO(davidmorgan): reconcile differences.
if (isNative) {
await expectModifyEvent('link.txt');
} else {
await expectNoEvents();
}
});
}
28 changes: 28 additions & 0 deletions pkgs/watcher/test/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,34 @@ void writeFile(String path, {String? contents, bool? updateModified}) {
}
}

/// Schedules writing a file in the sandbox at [link] pointing to [target].
///
/// If [updateModified] is `false`, the mock file modification time is not
/// changed.
void writeLink({
required String link,
required String target,
bool? updateModified,
}) {
updateModified ??= true;

var fullPath = p.join(d.sandbox, link);

// Create any needed subdirectories.
var dir = Directory(p.dirname(fullPath));
if (!dir.existsSync()) {
dir.createSync(recursive: true);
}

Link(fullPath).createSync(target);

if (updateModified) {
link = p.normalize(link);

_mockFileModificationTimes[link] = _nextTimestamp++;
}
}

/// Schedules deleting a file in the sandbox at [path].
void deleteFile(String path) {
File(p.join(d.sandbox, path)).deleteSync();
Expand Down
Loading