chore(web_file_system): sync changes from open_xml including idb_block_store, getAsBlob, and tests

This commit is contained in:
2026-06-10 21:35:21 -07:00
parent afb6302f0d
commit a627abc813
17 changed files with 1037 additions and 1923 deletions
@@ -0,0 +1,94 @@
@TestOn('browser')
import 'dart:convert';
import 'package:test/test.dart';
import 'package:web_file_system/web_file_system.dart';
void main() {
late WebFileSystem fs;
setUp(() async {
// Tests run in parallel in browser often sharing context, so use unique paths.
fs = WebFileSystem();
});
group('Troubleshooting NotFoundError', () {
test('Temp directory creation and persistence', () async {
print('DEBUG: creating temp dir');
final tempDir = await fs.systemTempDirectory.createTemp('debug_test_');
print('DEBUG: Created temp dir at ${tempDir.path}');
expect(await tempDir.exists(), isTrue);
final file = tempDir.childFile('test.txt');
await file.writeAsString('Persistence Check');
print('DEBUG: checking existence immediately');
expect(await file.exists(), isTrue);
expect(await file.readAsString(), equals('Persistence Check'));
// Wait a bit to simulate pipeline delays
await Future.delayed(const Duration(milliseconds: 500));
print('DEBUG: checking existence after delay');
expect(await file.readAsString(), equals('Persistence Check'));
// Cleanup
await tempDir.delete(recursive: true);
print('DEBUG: deleted temp dir');
expect(await file.exists(), isFalse);
});
test('Deep copy behavior verification', () async {
final srcDir = await fs.systemTempDirectory.createTemp('src_');
final destDir = await fs.systemTempDirectory.createTemp('dest_');
final srcFile = srcDir.childFile('source.dat');
// Write some substantial data
final data = utf8.encode('Essential Data for Export');
await srcFile.writeAsBytes(data);
print('DEBUG: Source file written to ${srcFile.path}');
final destPath = destDir.childFile('copy.dat').path;
print('DEBUG: Copying to $destPath');
final copiedFile = await srcFile.copy(destPath);
print('DEBUG: Copy complete');
expect(await copiedFile.exists(), isTrue);
expect(await copiedFile.readAsBytes(), equals(data));
// Now delete source
print('DEBUG: Deleting source file');
await srcFile.delete();
expect(await srcFile.exists(), isFalse);
// Verify copy still exists and is readable (Deep Copy Check)
print('DEBUG: Verifying copy after source deletion');
expect(await copiedFile.exists(), isTrue);
try {
final copyData = await copiedFile.readAsBytes();
expect(copyData, equals(data));
print('DEBUG: Deep copy verified!');
} catch (e) {
print('ERROR: Deep copy failed! Reading copy caused error: $e');
rethrow;
}
});
test('Concurrent Write/Read stress', () async {
final dir = await fs.systemTempDirectory.createTemp('stress_');
final file = dir.childFile('stress.txt');
// Write
await file.writeAsString('Initial');
// Rapidly update
for (int i = 0; i < 10; i++) {
await file.writeAsString('Update $i');
final content = await file.readAsString();
expect(content, equals('Update $i'));
}
});
});
}
@@ -0,0 +1,113 @@
@TestOn('browser')
import 'dart:async';
import 'dart:typed_data';
import 'package:test/test.dart';
import 'package:web_file_system/web_file_system.dart';
void main() {
late WebFileSystem fs;
setUp(() async {
fs = WebFileSystem();
});
group('Robust Correctness Tests', () {
test('Multiple files in a directory stress test', () async {
final uniqueId = DateTime.now().millisecondsSinceEpoch;
final dirPath = '/stress_$uniqueId';
final dir = fs.directory(dirPath);
await dir.create();
final fileCount = 50;
final futures = <Future>[];
for (var i = 0; i < fileCount; i++) {
futures.add(
fs.file('$dirPath/file_$i.txt').writeAsString('Content of file $i'),
);
}
await Future.wait(futures);
final entities = await dir.list().toList();
expect(entities.length, equals(fileCount));
final names = entities.map((e) => fs.path.basename(e.path)).toSet();
for (var i = 0; i < fileCount; i++) {
expect(names, contains('file_$i.txt'));
final content = await fs.file('$dirPath/file_$i.txt').readAsString();
expect(content, equals('Content of file $i'));
}
});
test('Temporary directory usage', () async {
final tempDir = await fs.systemTempDirectory.createTemp('my_prefix_');
expect(tempDir.path, startsWith('/tmp/my_prefix_'));
expect(await tempDir.exists(), isTrue);
final file = fs.file(fs.path.join(tempDir.path, 'test.txt'));
await file.writeAsString('temp content');
expect(await file.readAsString(), equals('temp content'));
await tempDir.delete(recursive: true);
expect(await tempDir.exists(), isFalse);
expect(await file.exists(), isFalse);
});
test('Different files with the same bytes (deduplication/collision check)', () async {
final uniqueId = DateTime.now().millisecondsSinceEpoch;
final data = Uint8List.fromList([1, 2, 3, 4, 5]);
final file1 = fs.file('/file1_$uniqueId.bin');
final file2 = fs.file('/file2_$uniqueId.bin');
await file1.writeAsBytes(data);
await file2.writeAsBytes(data);
expect(await file1.readAsBytes(), equals(data));
expect(await file2.readAsBytes(), equals(data));
// Update one, ensure other is unchanged
final newData = Uint8List.fromList([6, 7, 8]);
await file1.writeAsBytes(newData);
expect(await file1.readAsBytes(), equals(newData));
expect(await file2.readAsBytes(), equals(data));
// Cleanup
await file1.delete();
await file2.delete();
expect(await file1.exists(), isFalse);
expect(await file2.exists(), isFalse);
});
test('Resource cleanup verification (Blob leak check)', () async {
final uniqueId = DateTime.now().millisecondsSinceEpoch;
final filePath = '/leak_test_$uniqueId.bin';
final data = Uint8List.fromList(List.generate(100, (i) => i));
final file = fs.file(filePath);
await file.writeAsBytes(data);
final inode = await fs.resolvepath(filePath);
final blobId = inode.blobId;
expect(blobId, isNotNull);
// Verify blob exists in store
if (inode.storageType == 1) {
expect(await fs.idbStore.getBlob(blobId!), isNotNull);
} else {
expect(await fs.opfs.getBlob(blobId!), isNotNull);
}
await file.delete();
// Verify blob is gone
if (inode.storageType == 1) {
expect(() => fs.idbStore.getBlob(blobId!), throwsA(anything));
} else {
expect(() => fs.opfs.getBlob(blobId!), throwsA(anything));
}
});
});
}
File diff suppressed because it is too large Load Diff