Skip to content

Commit

Permalink
Merge pull request #80 from a-givertzman/TextFile-read-fix
Browse files Browse the repository at this point in the history
Text file read fix
  • Loading branch information
a-givertzman authored Mar 4, 2024
2 parents 966dc96 + 3854c7e commit 91632bf
Show file tree
Hide file tree
Showing 14 changed files with 211 additions and 75 deletions.
9 changes: 8 additions & 1 deletion lib/src/app_settings/app_settings.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import 'package:hmi_core/src/core/error/failure.dart';
import 'package:hmi_core/src/core/json/json_map.dart';
import 'package:hmi_core/src/core/log/log.dart';
import 'package:hmi_core/src/core/log/log_level.dart';
import 'package:hmi_core/src/core/result_new/result.dart';
///
class AppSettings {
static final _log = const Log('AppSettings')..level=LogLevel.info;
static final _map = <String, dynamic>{
'displaySizeWidth': 1024,
'displaySizeHeight': 768,
Expand All @@ -19,7 +23,10 @@ class AppSettings {
static Future<void> initialize({JsonMap<dynamic>? jsonMap}) async {
if (jsonMap != null) {
await jsonMap.decoded
.then((map) => _map.addAll(map));
.then((result) => switch(result) {
Ok(value: final map) => _map.addAll(map),
Err() => _log.warning('Failed to initialize app settings from file.'),
});
}
}
///
Expand Down
39 changes: 32 additions & 7 deletions lib/src/core/json/json_list.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,39 @@
import 'dart:async';
import 'dart:convert';

import 'package:hmi_core/src/core/error/failure.dart';
import 'package:hmi_core/src/core/log/log.dart';
import 'package:hmi_core/src/core/log/log_level.dart';
import 'package:hmi_core/src/core/result_new/result.dart';
import 'package:hmi_core/src/core/text_file.dart';
///
class JsonList<T> {
final FutureOr<String> _content;
const JsonList(String content) : _content = content;
JsonList.fromTextFile(TextFile textFile) : _content = textFile.content;
Future<List<T>> get decoded async {
final map = const JsonCodec().decode(await _content) as List<dynamic>;
return map.cast<T>();
static final _log = const Log('JsonList')..level=LogLevel.info;
final FutureOr<ResultF<String>> _content;
const JsonList._(FutureOr<ResultF<String>> content) : _content = content;
JsonList.fromString(String content) : this._(Ok(content));
JsonList.fromTextFile(TextFile textFile) : this._(textFile.content);
///
Future<ResultF<List<T>>> get decoded async {
const failureMessage = 'Failed to parse json list from file.';
switch(await _content) {
case Ok(:final value):
try {
final decodedJson = const JsonCodec().decode(value) as List<dynamic>;
return Ok(
decodedJson.cast<T>(),
);
} catch(error) {
_log.warning(failureMessage);
return Err(
Failure(
message: error.toString(),
stackTrace: StackTrace.current,
),
);
}
case Err(:final error):
_log.warning(failureMessage);
return Err(error);
}
}
}
39 changes: 32 additions & 7 deletions lib/src/core/json/json_map.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,39 @@
import 'dart:async';
import 'dart:convert';

import 'package:hmi_core/src/core/error/failure.dart';
import 'package:hmi_core/src/core/log/log.dart';
import 'package:hmi_core/src/core/log/log_level.dart';
import 'package:hmi_core/src/core/result_new/result.dart';
import 'package:hmi_core/src/core/text_file.dart';
///
class JsonMap<T> {
final FutureOr<String> _content;
const JsonMap(String content) : _content = content;
JsonMap.fromTextFile(TextFile textFile) : _content = textFile.content;
Future<Map<String, T>> get decoded async {
final map = const JsonCodec().decode(await _content) as Map<String, dynamic>;
return map.cast<String, T>();
static final _log = const Log('JsonMap')..level=LogLevel.info;
final FutureOr<ResultF<String>> _content;
const JsonMap._(FutureOr<ResultF<String>> content) : _content = content;
JsonMap.fromString(String content) : this._(Ok(content));
JsonMap.fromTextFile(TextFile textFile) : this._(textFile.content);
///
Future<ResultF<Map<String, T>>> get decoded async {
const failureMessage = 'Failed to parse json map from file.';
switch(await _content) {
case Ok(:final value):
try {
final decodedJson = const JsonCodec().decode(value) as Map<String,dynamic>;
return Ok(
decodedJson.cast<String,T>(),
);
} catch(error) {
_log.warning(failureMessage);
return Err(
Failure(
message: error.toString(),
stackTrace: StackTrace.current,
),
);
}
case Err(:final error):
_log.warning(failureMessage);
return Err(error);
}
}
}
40 changes: 36 additions & 4 deletions lib/src/core/text_file.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:hmi_core/hmi_core.dart';
import 'package:hmi_core/src/core/result_new/result.dart';
/// The interface for reading and writing a text file.
abstract interface class TextFile {
/// Text file from the file system.
Expand All @@ -11,30 +13,60 @@ abstract interface class TextFile {
/// `assetPath` - path to the file according to your `assets` section in `pubspec.yaml`.
const factory TextFile.asset(String assetPath) = _AssetTextFile;
///
/// Internal file contents as text.
Future<String> get content;
/// Internal file contents as text.
///
/// Returns [Ok] with text if file exists and [Err] with error otherwise.
Future<ResultF<String>> get content;
///
/// Rewrites the entire file with provided `text`.
Future<void> write(String text);
}
///
class _PathTextFile implements TextFile {
static final _log = const Log('_PathTextFile')..level=LogLevel.info;
final String _filePath;
const _PathTextFile(this._filePath);
//
@override
Future<String> get content => File(_filePath).readAsString();
Future<ResultF<String>> get content async {
final file = File(_filePath);
switch(await file.exists()) {
case true:
return Ok(await file.readAsString());
case false:
_log.warning('Failed to read from file.');
return Err(
Failure(
message: 'File $_filePath does not exist.',
stackTrace: StackTrace.current,
),
);
}
}
//
@override
Future<void> write(String text) => File(_filePath).writeAsString(text, flush: true);
}
///
class _AssetTextFile implements TextFile {
static final _log = const Log('_AssetTextFile')..level=LogLevel.info;
final String _assetPath;
const _AssetTextFile(this._assetPath);
//
@override
Future<String> get content => rootBundle.loadString(_assetPath);
Future<ResultF<String>> get content {
return rootBundle.loadString(_assetPath)
.then<ResultF<String>>((value) => Ok(value))
.catchError((error) {
_log.warning('Failed to read from asset.');
return Err<String, Failure>(
Failure(
message: error.toString(),
stackTrace: StackTrace.current,
),
);
});
}
//
@override
Future<void> write(String text) {
Expand Down
18 changes: 14 additions & 4 deletions lib/src/translate/localizations.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:hmi_core/hmi_core_log.dart';
import 'package:hmi_core/src/core/json/json_map.dart';
import 'package:hmi_core/src/core/result_new/result.dart';
import 'package:hmi_core/src/translate/app_lang.dart';
///
class Localizations {
Expand Down Expand Up @@ -240,10 +241,19 @@ class Localizations {
_appLang = appLang;
if (jsonMap != null) {
await jsonMap.decoded
.then((map) => map.map(
(key, value) => MapEntry(key, value.cast<String>()),
))
.then((map) => _map.addAll(map));
.then((result) {
switch(result) {
case Ok(value:final map):
final localizationsMap = map.map(
(key, value) => MapEntry(key, value.cast<String>()),
);
_map.addAll(localizationsMap);
break;
case Err():
_log.warning('Failed to initialize localizations from file.');
break;
}
});
}
}
///
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: hmi_core
description: A Flutter core package of hmi_widgets package which is helps to visualize states, values, changes and other artefacts from technological processes.
version: 0.0.5
version: 1.0.0
homepage: https://github.com/a-givertzman/hmi_core

environment:
Expand Down
2 changes: 1 addition & 1 deletion test/unit/auth/user_password_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ void main() {
Log.initialize(level: LogLevel.all);
const log = Log('UserPassword');
AppSettings.initialize(
jsonMap: const JsonMap('{"passwordKey": "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNMЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЁЯЧСМИТЬБЮйцукенгшщзхъфывапролджэёячсмитьбю"}'),
jsonMap: JsonMap.fromString('{"passwordKey": "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNMЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЁЯЧСМИТЬБЮйцукенгшщзхъфывапролджэёячсмитьбю"}'),
);
test('value', () async {
const rawPassValue = '123qwe';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:hmi_core/hmi_core.dart';

import 'fake_text_file.dart';
import 'settings_data.dart';

void main() {
Log.initialize();
group('AppUiSettings initialize', () {
test('sets data normally with valid json format and valid data', () async {
for (final settings in validSettings) {
Expand Down Expand Up @@ -33,16 +33,15 @@ void main() {
// );
// }
// });
test('throws with invalid json format', () {
test('does not throw with invalid json format', () {
for (final invalidJson in invalidJsons) {
final textFile = invalidJson['text_file'] as String;
expect(
() => AppSettings.initialize(
expectLater(AppSettings.initialize(
jsonMap: JsonMap.fromTextFile(
FakeTextFile(textFile),
),
),
throwsA(isA<FormatException>()),
completes,
);
}
});
Expand Down
3 changes: 2 additions & 1 deletion test/unit/core/entities/app_settings/fake_text_file.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:hmi_core/src/core/result_new/result.dart';
import 'package:hmi_core/src/core/text_file.dart';
///
class FakeTextFile implements TextFile {
Expand All @@ -6,7 +7,7 @@ class FakeTextFile implements TextFile {
const FakeTextFile(this.text, {this.writeFuture});
//
@override
Future<String> get content => Future.value(text);
Future<ResultF<String>> get content => Future.value(Ok(text));
//
@override
Future<void> write(String text) => writeFuture ?? Future(() {return;});
Expand Down
9 changes: 4 additions & 5 deletions test/unit/core/entities/app_settings/setting_test.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:hmi_core/hmi_core.dart';
import 'package:hmi_core/hmi_core_app_settings.dart';

import 'fake_text_file.dart';
import 'settings_data.dart';

void main() {
Log.initialize();
group('Setting', () {
Log.initialize(level: LogLevel.all);
const log = Log('Setting');
Expand Down Expand Up @@ -72,16 +72,15 @@ void main() {
}
}
});
test('throws with invalid json', () {
test('does not throw with invalid json', () {
for (final invalidJson in invalidJsons) {
final textFile = invalidJson['text_file'] as String;
expect(
() => AppSettings.initialize(
expectLater(AppSettings.initialize(
jsonMap: JsonMap.fromTextFile(
FakeTextFile(textFile),
),
),
throwsA(isA<FormatException>()),
completes,
);
}
});
Expand Down
Loading

0 comments on commit 91632bf

Please sign in to comment.