From 4fcc6d91200b236f8d9d8b0573ae4117d524da1f Mon Sep 17 00:00:00 2001 From: Vishesh Handa Date: Mon, 21 May 2018 15:31:34 +0200 Subject: [PATCH] Add a FileStorage class With a test! --- lib/file_storage.dart | 51 +++++++++++++++++++++++++++++++++++++ lib/note.dart | 34 +++++++++++++++++++++++-- pubspec.lock | 2 +- pubspec.yaml | 2 +- test/file_storage_test.dart | 40 +++++++++++++++++++++++++++++ test/widget_test.dart | 29 --------------------- 6 files changed, 125 insertions(+), 33 deletions(-) create mode 100644 lib/file_storage.dart create mode 100644 test/file_storage_test.dart delete mode 100644 test/widget_test.dart diff --git a/lib/file_storage.dart b/lib/file_storage.dart new file mode 100644 index 00000000..b7371691 --- /dev/null +++ b/lib/file_storage.dart @@ -0,0 +1,51 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:convert'; + +import 'package:path/path.dart' as p; + +import './note.dart'; + +class FileStorage { + final Future Function() getDirectory; + + FileStorage(this.getDirectory); + + Future> loadNotes() async { + final dir = await getDirectory(); + + var notes = new List(); + var lister = dir.list(recursive: false); + await for (var fileEntity in lister) { + Note note = await _loadNote(fileEntity); + notes.add(note); + } + + return notes; + } + + Future _loadNote(FileSystemEntity entity) async { + if (entity is! File) { + return null; + } + var file = entity as File; + final string = await file.readAsString(); + final json = JsonDecoder().convert(string); + return new Note.fromJson(json); + } + + Future saveNotes(List notes) async { + final dir = await getDirectory(); + //await dir.delete(recursive: true); + + for (var note in notes) { + var filePath = p.join(dir.path, note.id); + + var file = new File(filePath); + var contents = JsonEncoder().convert(note.toJson()); + await file.writeAsString(contents); + } + + return dir; + } +} diff --git a/lib/note.dart b/lib/note.dart index dd8f772e..0c9f7ff3 100644 --- a/lib/note.dart +++ b/lib/note.dart @@ -1,13 +1,43 @@ -class Note { +class Note implements Comparable { + final String id; final DateTime createdAt; final String body; - const Note({this.createdAt, this.body}); + const Note({this.createdAt, this.body, this.id}); factory Note.fromJson(Map json) { return new Note( + id: json['id'], createdAt: DateTime.parse(json['createdAt']), body: json['body'], ); } + + Map toJson() { + return { + "createdAt": createdAt.toIso8601String(), + "body": body, + "id": id, + }; + } + + @override + int get hashCode => id.hashCode ^ createdAt.hashCode ^ body.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Note && + runtimeType == other.runtimeType && + id == other.id && + body == other.body && + createdAt == other.createdAt; + + @override + String toString() { + return 'Note{id: $id, body: $body, createdAt: $createdAt}'; + } + + @override + int compareTo(other) => createdAt.compareTo(other.createdAt); } diff --git a/pubspec.lock b/pubspec.lock index 5e65f110..a7c2b42e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -222,7 +222,7 @@ packages: source: hosted version: "1.0.2" path: - dependency: transitive + dependency: "direct main" description: name: path url: "https://pub.dartlang.org" diff --git a/pubspec.yaml b/pubspec.yaml index b79e0352..331eddc2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ dependencies: sdk: flutter http: "^0.11.3+16" intl: "^0.15.6" - + path: "^1.5.1" dev_dependencies: flutter_test: diff --git a/test/file_storage_test.dart b/test/file_storage_test.dart new file mode 100644 index 00000000..a8fd4118 --- /dev/null +++ b/test/file_storage_test.dart @@ -0,0 +1,40 @@ +import 'dart:io'; + +import 'package:test/test.dart'; +import 'package:path/path.dart' as p; + +import '../lib/note.dart'; +import '../lib/file_storage.dart'; + +main() { + group('FileStorage', () { + var notes = [ + Note(id: "1", body: "test", createdAt: new DateTime.now()), + Note(id: "2", body: "test2", createdAt: new DateTime.now()), + ]; + + final directory = Directory.systemTemp.createTemp('__storage_test__'); + final storage = FileStorage(() => directory); + + tearDownAll(() async { + final tempDirectory = await directory; + tempDirectory.deleteSync(recursive: true); + }); + + test('Should persist Notes to disk', () async { + var dir = await storage.saveNotes(notes); + expect(dir.listSync(recursive: true).length, 2); + + expect(File(p.join(dir.path, "1")).existsSync(), isTrue); + expect(File(p.join(dir.path, "2")).existsSync(), isTrue); + }); + + test('Should load Notes from disk', () async { + var loadedNotes = await storage.loadNotes(); + loadedNotes.sort(); + notes.sort(); + + expect(loadedNotes, notes); + }); + }); +} diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index 51c6c538..00000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,29 +0,0 @@ -// This is a basic Flutter widget test. -// To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter -// provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to -// find child widgets in the widget tree, read text, and verify that the values of widget properties -// are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:journal/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(new MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -}