Add copy and open operation handles to inject memory file exceptions without mocking (#184)
diff --git a/packages/file/CHANGELOG.md b/packages/file/CHANGELOG.md
index 4bf571e..69175de 100644
--- a/packages/file/CHANGELOG.md
+++ b/packages/file/CHANGELOG.md
@@ -1,8 +1,12 @@
+#### 6.1.1
+
+* `MemoryFile` now provides `opHandle`s for copy and open operations.
+
#### 6.1.0
* Reading invalid UTF8 with the `MemoryFileSystem` now correctly throws a `FileSystemException` instead of a `FormatError`.
* `MemoryFileSystem` now provides an `opHandle` to inspect read/write operations.
-* `MemoryFileSystem` now creates the tempory directory before returning in `createTemp`/`createTempSync`.
+* `MemoryFileSystem` now creates the temporary directory before returning in `createTemp`/`createTempSync`.
#### 6.0.1
diff --git a/packages/file/lib/src/backends/memory/memory_file.dart b/packages/file/lib/src/backends/memory/memory_file.dart
index a3ce724..988ffd2 100644
--- a/packages/file/lib/src/backends/memory/memory_file.dart
+++ b/packages/file/lib/src/backends/memory/memory_file.dart
@@ -98,6 +98,7 @@
@override
File copySync(String newPath) {
+ fileSystem.opHandle(path, FileSystemOp.copy);
FileNode sourceNode = resolvedBacking as FileNode;
fileSystem.findNode(
newPath,
@@ -180,6 +181,7 @@
@override
io.RandomAccessFile openSync({io.FileMode mode = io.FileMode.read}) {
+ fileSystem.opHandle(path, FileSystemOp.open);
if (utils.isWriteMode(mode) && !existsSync()) {
// [resolvedBacking] requires that the file already exists, so we must
// create it here first.
@@ -191,6 +193,7 @@
@override
Stream<Uint8List> openRead([int? start, int? end]) {
+ fileSystem.opHandle(path, FileSystemOp.open);
try {
FileNode node = resolvedBacking as FileNode;
Uint8List content = node.content;
@@ -210,6 +213,7 @@
io.FileMode mode = io.FileMode.write,
Encoding encoding = utf8,
}) {
+ fileSystem.opHandle(path, FileSystemOp.open);
if (!utils.isWriteMode(mode)) {
throw ArgumentError.value(mode, 'mode',
'Must be either WRITE, APPEND, WRITE_ONLY, or WRITE_ONLY_APPEND');
diff --git a/packages/file/lib/src/backends/memory/operations.dart b/packages/file/lib/src/backends/memory/operations.dart
index a3e47f4..e0bf55f 100644
--- a/packages/file/lib/src/backends/memory/operations.dart
+++ b/packages/file/lib/src/backends/memory/operations.dart
@@ -42,6 +42,20 @@
/// * [FileSystemEntity.createSync]
static const FileSystemOp create = FileSystemOp._(3);
+ /// A file operation used for all open methods.
+ ///
+ /// * [File.open]
+ /// * [File.openSync]
+ /// * [File.openRead]
+ /// * [File.openWrite]
+ static const FileSystemOp open = FileSystemOp._(4);
+
+ /// A file operation used for all copy methods.
+ ///
+ /// * [File.copy]
+ /// * [File.copySync]
+ static const FileSystemOp copy = FileSystemOp._(5);
+
@override
String toString() {
switch (_value) {
@@ -53,6 +67,10 @@
return 'FileSystemOp.delete';
case 3:
return 'FileSystemOp.create';
+ case 4:
+ return 'FileSystemOp.open';
+ case 5:
+ return 'FileSystemOp.copy';
default:
throw StateError('Invalid FileSytemOp type: $this');
}
diff --git a/packages/file/pubspec.yaml b/packages/file/pubspec.yaml
index a627171..14ac96a 100644
--- a/packages/file/pubspec.yaml
+++ b/packages/file/pubspec.yaml
@@ -1,5 +1,5 @@
name: file
-version: 6.1.0
+version: 6.1.1
description:
A pluggable, mockable file system abstraction for Dart. Supports local file
system access, as well as in-memory file systems, record-replay file systems,
diff --git a/packages/file/test/memory_operations_test.dart b/packages/file/test/memory_operations_test.dart
index e878317..2efa569 100644
--- a/packages/file/test/memory_operations_test.dart
+++ b/packages/file/test/memory_operations_test.dart
@@ -139,6 +139,54 @@
]);
});
+ test('Open operations invoke opHandle', () async {
+ List<String> contexts = <String>[];
+ List<FileSystemOp> operations = <FileSystemOp>[];
+ MemoryFileSystem fs = MemoryFileSystem.test(
+ opHandle: (String context, FileSystemOp operation) {
+ if (operation == FileSystemOp.open) {
+ contexts.add(context);
+ operations.add(operation);
+ }
+ });
+ final File file = fs.file('test')..createSync();
+
+ await file.open();
+ file.openSync();
+ file.openRead();
+ file.openWrite();
+
+ expect(contexts, <String>['test', 'test', 'test', 'test']);
+ expect(operations, <FileSystemOp>[
+ FileSystemOp.open,
+ FileSystemOp.open,
+ FileSystemOp.open,
+ FileSystemOp.open,
+ ]);
+ });
+
+ test('Copy operations invoke opHandle', () async {
+ List<String> contexts = <String>[];
+ List<FileSystemOp> operations = <FileSystemOp>[];
+ MemoryFileSystem fs = MemoryFileSystem.test(
+ opHandle: (String context, FileSystemOp operation) {
+ if (operation == FileSystemOp.copy) {
+ contexts.add(context);
+ operations.add(operation);
+ }
+ });
+ final File file = fs.file('test')..createSync();
+
+ await file.copy('A');
+ file.copySync('B');
+
+ expect(contexts, <String>['test', 'test']);
+ expect(operations, <FileSystemOp>[
+ FileSystemOp.copy,
+ FileSystemOp.copy,
+ ]);
+ });
+
test('FileSystemOp toString', () {
expect(FileSystemOp.create.toString(), 'FileSystemOp.create');
expect(FileSystemOp.delete.toString(), 'FileSystemOp.delete');