diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cb3e7cf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.dart_tool/ diff --git a/analysis_options.yaml b/analysis_options.yaml index 2b1e1b3..98195c2 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -7,7 +7,6 @@ analyzer: linter: rules: - - public_member_api_docs - prefer_final_fields - prefer_const_constructors - prefer_const_declarations diff --git a/lib/src/file_actor.dart b/lib/src/file_actor.dart new file mode 100644 index 0000000..fa1ebcf --- /dev/null +++ b/lib/src/file_actor.dart @@ -0,0 +1,39 @@ +import 'dart:io'; +import 'package:actors/actors.dart'; + +sealed class FileMessage { + const FileMessage(); +} + +final class LoadFile extends FileMessage { + final String path; + const LoadFile(this.path); +} + +final class SaveFile extends FileMessage { + final String path; + final String content; + const SaveFile(this.path, this.content); +} + +sealed class FileResult { + const FileResult(); +} + +final class FileLoaded extends FileResult { + final String content; + const FileLoaded(this.content); +} + +final class FileSaved extends FileResult { + const FileSaved(); +} + +class FileActor with Handler { + @override + Future handle(FileMessage message) => switch (message) { + LoadFile(:final path) => File(path).readAsString().then(FileLoaded.new), + SaveFile(:final path, :final content) => + File(path).writeAsString(content).then((_) => const FileSaved()), + }; +} diff --git a/lib/swarm.dart b/lib/swarm.dart new file mode 100644 index 0000000..aff0d0c --- /dev/null +++ b/lib/swarm.dart @@ -0,0 +1 @@ +export 'src/file_actor.dart'; diff --git a/test/file_actor_test.dart b/test/file_actor_test.dart new file mode 100644 index 0000000..ef2f6f5 --- /dev/null +++ b/test/file_actor_test.dart @@ -0,0 +1,42 @@ +import 'dart:io'; +import 'package:actors/actors.dart'; +import 'package:swarm/swarm.dart'; +import 'package:test/test.dart'; + +void main() { + group('FileActor', () { + late Actor actor; + late Directory tempDir; + + setUp(() async { + actor = Actor.create(FileActor.new); + tempDir = await Directory.systemTemp.createTemp('swarm_test_'); + }); + + tearDown(() async { + await actor.close(); + await tempDir.delete(recursive: true); + }); + + test('saves a file', () async { + final path = '${tempDir.path}/hello.txt'; + final result = await actor.send(SaveFile(path, 'hello world')); + expect(result, isA()); + }); + + test('loads a saved file', () async { + final path = '${tempDir.path}/hello.txt'; + await actor.send(SaveFile(path, 'hello world')); + final result = await actor.send(LoadFile(path)); + expect(result, isA()); + expect((result as FileLoaded).content, equals('hello world')); + }); + + test('load throws PathNotFoundException for missing file', () { + expect( + actor.send(LoadFile('${tempDir.path}/nonexistent.txt')), + throwsA(isA()), + ); + }); + }); +}