test: add more provider tests

This commit is contained in:
Tien Do Nam
2023-12-17 15:17:46 +01:00
parent fe6ab3e431
commit a98273f09f
11 changed files with 1151 additions and 31 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ class ReceiveHistoryPage extends StatelessWidget {
Future<void> _openFile(
BuildContext context,
ReceiveHistoryEntry entry,
Dispatcher<ReceiveHistoryNotifier, List<ReceiveHistoryEntry>> dispatcher,
Dispatcher<ReceiveHistoryService, List<ReceiveHistoryEntry>> dispatcher,
) async {
if (entry.path != null) {
await openFile(
+10 -1
View File
@@ -43,6 +43,10 @@ class UpdateFavoriteAction extends AsyncReduxAction<FavoritesService, List<Favor
@override
Future<List<FavoriteDevice>> reduce() async {
final index = state.indexWhere((e) => e.id == device.id);
if (index == -1) {
// Unknown device
return state;
}
final updated = List<FavoriteDevice>.unmodifiable(<FavoriteDevice>[
...state,
]..replaceRange(index, index + 1, [device]));
@@ -61,9 +65,14 @@ class RemoveFavoriteAction extends AsyncReduxAction<FavoritesService, List<Favor
@override
Future<List<FavoriteDevice>> reduce() async {
final index = state.indexWhere((e) => e.fingerprint == deviceFingerprint);
if (index == -1) {
// Unknown device
return state;
}
final updated = List<FavoriteDevice>.unmodifiable(<FavoriteDevice>[
...state,
]..removeWhere((e) => e.fingerprint == deviceFingerprint));
]..removeAt(index));
await notifier._persistence.setFavorites(updated);
return updated;
}
+4 -4
View File
@@ -4,17 +4,17 @@ import 'package:refena_flutter/refena_flutter.dart';
/// This provider stores the last devices that the user sent a file to.
/// It stores only the last 5 devices that were selected by be [AddressInputDialog].
/// The information is **not** persisted.
final lastDevicesProvider = ReduxProvider<LastDevicesNotifier, List<Device>>((ref) {
return LastDevicesNotifier();
final lastDevicesProvider = ReduxProvider<LastDevicesService, List<Device>>((ref) {
return LastDevicesService();
});
class LastDevicesNotifier extends ReduxNotifier<List<Device>> {
class LastDevicesService extends ReduxNotifier<List<Device>> {
@override
List<Device> init() => [];
}
/// Adds a device to the list of last devices.
class AddLastDeviceAction extends ReduxAction<LastDevicesNotifier, List<Device>> {
class AddLastDeviceAction extends ReduxAction<LastDevicesService, List<Device>> {
final Device device;
AddLastDeviceAction(this.device);
+12 -8
View File
@@ -5,21 +5,21 @@ import 'package:refena_flutter/refena_flutter.dart';
/// This provider stores the history of received files.
/// It automatically saves the history to the device's storage.
final receiveHistoryProvider = ReduxProvider<ReceiveHistoryNotifier, List<ReceiveHistoryEntry>>((ref) {
return ReceiveHistoryNotifier(ref.read(persistenceProvider));
final receiveHistoryProvider = ReduxProvider<ReceiveHistoryService, List<ReceiveHistoryEntry>>((ref) {
return ReceiveHistoryService(ref.read(persistenceProvider));
});
class ReceiveHistoryNotifier extends ReduxNotifier<List<ReceiveHistoryEntry>> {
class ReceiveHistoryService extends ReduxNotifier<List<ReceiveHistoryEntry>> {
final PersistenceService _persistence;
ReceiveHistoryNotifier(this._persistence);
ReceiveHistoryService(this._persistence);
@override
List<ReceiveHistoryEntry> init() => _persistence.getReceiveHistory();
}
/// Adds a history entry.
class AddHistoryEntryAction extends AsyncReduxAction<ReceiveHistoryNotifier, List<ReceiveHistoryEntry>> {
class AddHistoryEntryAction extends AsyncReduxAction<ReceiveHistoryService, List<ReceiveHistoryEntry>> {
final String entryId;
final String fileName;
final FileType fileType;
@@ -65,21 +65,25 @@ class AddHistoryEntryAction extends AsyncReduxAction<ReceiveHistoryNotifier, Lis
}
/// Removes a history entry.
class RemoveHistoryEntryAction extends AsyncReduxAction<ReceiveHistoryNotifier, List<ReceiveHistoryEntry>> {
class RemoveHistoryEntryAction extends AsyncReduxAction<ReceiveHistoryService, List<ReceiveHistoryEntry>> {
final String entryId;
RemoveHistoryEntryAction(this.entryId);
@override
Future<List<ReceiveHistoryEntry>> reduce() async {
final updated = [...state]..removeWhere((e) => e.id == entryId);
final index = state.indexWhere((e) => e.id == entryId);
if (index == -1) {
return state;
}
final updated = [...state]..removeAt(index);
await notifier._persistence.setReceiveHistory(updated);
return updated;
}
}
/// Removes all history entries.
class RemoveAllHistoryEntriesAction extends AsyncReduxAction<ReceiveHistoryNotifier, List<ReceiveHistoryEntry>> {
class RemoveAllHistoryEntriesAction extends AsyncReduxAction<ReceiveHistoryService, List<ReceiveHistoryEntry>> {
@override
Future<List<ReceiveHistoryEntry>> reduce() async {
await notifier._persistence.setReceiveHistory([]);
+8
View File
@@ -860,6 +860,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.4"
mockito:
dependency: "direct dev"
description:
name: mockito
sha256: "6841eed20a7befac0ce07df8116c8b8233ed1f4486a7647c7fc5a02ae6163917"
url: "https://pub.dev"
source: hosted
version: "5.4.4"
msix:
dependency: "direct dev"
description:
+1
View File
@@ -77,6 +77,7 @@ dev_dependencies:
dart_mappable_builder: 4.0.1
flutter_gen_runner: 5.3.2
flutter_lints: 3.0.1
mockito: 5.4.4
msix: 3.16.7
refena_inspector: 1.2.0
slang_build_runner: 3.26.1
+9
View File
@@ -0,0 +1,9 @@
import 'package:localsend_app/provider/persistence_provider.dart';
import 'package:mockito/annotations.dart';
import 'package:shared_preferences/shared_preferences.dart';
@GenerateNiceMocks([
MockSpec<PersistenceService>(),
MockSpec<SharedPreferences>(),
])
void main() {}
+804
View File
@@ -0,0 +1,804 @@
// Mocks generated by Mockito 5.4.4 from annotations
// in localsend_app/test/mocks.dart.
// Do not manually edit this file.
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i4;
import 'dart:ui' as _i12;
import 'package:flutter/material.dart' as _i8;
import 'package:localsend_app/gen/strings.g.dart' as _i10;
import 'package:localsend_app/model/device.dart' as _i13;
import 'package:localsend_app/model/persistence/color_mode.dart' as _i9;
import 'package:localsend_app/model/persistence/favorite_device.dart' as _i6;
import 'package:localsend_app/model/persistence/receive_history_entry.dart'
as _i5;
import 'package:localsend_app/model/persistence/stored_security_context.dart'
as _i2;
import 'package:localsend_app/model/send_mode.dart' as _i11;
import 'package:localsend_app/provider/persistence_provider.dart' as _i3;
import 'package:mockito/mockito.dart' as _i1;
import 'package:mockito/src/dummies.dart' as _i7;
import 'package:shared_preferences/shared_preferences.dart' as _i14;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
class _FakeStoredSecurityContext_0 extends _i1.SmartFake
implements _i2.StoredSecurityContext {
_FakeStoredSecurityContext_0(
Object parent,
Invocation parentInvocation,
) : super(
parent,
parentInvocation,
);
}
/// A class which mocks [PersistenceService].
///
/// See the documentation for Mockito's code generation for more information.
class MockPersistenceService extends _i1.Mock
implements _i3.PersistenceService {
@override
_i2.StoredSecurityContext getSecurityContext() => (super.noSuchMethod(
Invocation.method(
#getSecurityContext,
[],
),
returnValue: _FakeStoredSecurityContext_0(
this,
Invocation.method(
#getSecurityContext,
[],
),
),
returnValueForMissingStub: _FakeStoredSecurityContext_0(
this,
Invocation.method(
#getSecurityContext,
[],
),
),
) as _i2.StoredSecurityContext);
@override
_i4.Future<void> setSecurityContext(_i2.StoredSecurityContext? context) =>
(super.noSuchMethod(
Invocation.method(
#setSecurityContext,
[context],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
List<_i5.ReceiveHistoryEntry> getReceiveHistory() => (super.noSuchMethod(
Invocation.method(
#getReceiveHistory,
[],
),
returnValue: <_i5.ReceiveHistoryEntry>[],
returnValueForMissingStub: <_i5.ReceiveHistoryEntry>[],
) as List<_i5.ReceiveHistoryEntry>);
@override
_i4.Future<void> setReceiveHistory(List<_i5.ReceiveHistoryEntry>? entries) =>
(super.noSuchMethod(
Invocation.method(
#setReceiveHistory,
[entries],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
List<_i6.FavoriteDevice> getFavorites() => (super.noSuchMethod(
Invocation.method(
#getFavorites,
[],
),
returnValue: <_i6.FavoriteDevice>[],
returnValueForMissingStub: <_i6.FavoriteDevice>[],
) as List<_i6.FavoriteDevice>);
@override
_i4.Future<void> setFavorites(List<_i6.FavoriteDevice>? entries) =>
(super.noSuchMethod(
Invocation.method(
#setFavorites,
[entries],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
String getShowToken() => (super.noSuchMethod(
Invocation.method(
#getShowToken,
[],
),
returnValue: _i7.dummyValue<String>(
this,
Invocation.method(
#getShowToken,
[],
),
),
returnValueForMissingStub: _i7.dummyValue<String>(
this,
Invocation.method(
#getShowToken,
[],
),
),
) as String);
@override
String getAlias() => (super.noSuchMethod(
Invocation.method(
#getAlias,
[],
),
returnValue: _i7.dummyValue<String>(
this,
Invocation.method(
#getAlias,
[],
),
),
returnValueForMissingStub: _i7.dummyValue<String>(
this,
Invocation.method(
#getAlias,
[],
),
),
) as String);
@override
_i4.Future<void> setAlias(String? alias) => (super.noSuchMethod(
Invocation.method(
#setAlias,
[alias],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
_i8.ThemeMode getTheme() => (super.noSuchMethod(
Invocation.method(
#getTheme,
[],
),
returnValue: _i8.ThemeMode.system,
returnValueForMissingStub: _i8.ThemeMode.system,
) as _i8.ThemeMode);
@override
_i4.Future<void> setTheme(_i8.ThemeMode? theme) => (super.noSuchMethod(
Invocation.method(
#setTheme,
[theme],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
_i9.ColorMode getColorMode() => (super.noSuchMethod(
Invocation.method(
#getColorMode,
[],
),
returnValue: _i9.ColorMode.system,
returnValueForMissingStub: _i9.ColorMode.system,
) as _i9.ColorMode);
@override
_i4.Future<void> setColorMode(_i9.ColorMode? color) => (super.noSuchMethod(
Invocation.method(
#setColorMode,
[color],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
_i4.Future<void> setLocale(_i10.AppLocale? locale) => (super.noSuchMethod(
Invocation.method(
#setLocale,
[locale],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
int getPort() => (super.noSuchMethod(
Invocation.method(
#getPort,
[],
),
returnValue: 0,
returnValueForMissingStub: 0,
) as int);
@override
_i4.Future<void> setPort(int? port) => (super.noSuchMethod(
Invocation.method(
#setPort,
[port],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
String getMulticastGroup() => (super.noSuchMethod(
Invocation.method(
#getMulticastGroup,
[],
),
returnValue: _i7.dummyValue<String>(
this,
Invocation.method(
#getMulticastGroup,
[],
),
),
returnValueForMissingStub: _i7.dummyValue<String>(
this,
Invocation.method(
#getMulticastGroup,
[],
),
),
) as String);
@override
_i4.Future<void> setMulticastGroup(String? group) => (super.noSuchMethod(
Invocation.method(
#setMulticastGroup,
[group],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
_i4.Future<void> setDestination(String? destination) => (super.noSuchMethod(
Invocation.method(
#setDestination,
[destination],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
bool isSaveToGallery() => (super.noSuchMethod(
Invocation.method(
#isSaveToGallery,
[],
),
returnValue: false,
returnValueForMissingStub: false,
) as bool);
@override
_i4.Future<void> setSaveToGallery(bool? saveToGallery) => (super.noSuchMethod(
Invocation.method(
#setSaveToGallery,
[saveToGallery],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
bool isSaveToHistory() => (super.noSuchMethod(
Invocation.method(
#isSaveToHistory,
[],
),
returnValue: false,
returnValueForMissingStub: false,
) as bool);
@override
_i4.Future<void> setSaveToHistory(bool? saveToHistory) => (super.noSuchMethod(
Invocation.method(
#setSaveToHistory,
[saveToHistory],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
bool isQuickSave() => (super.noSuchMethod(
Invocation.method(
#isQuickSave,
[],
),
returnValue: false,
returnValueForMissingStub: false,
) as bool);
@override
_i4.Future<void> setQuickSave(bool? quickSave) => (super.noSuchMethod(
Invocation.method(
#setQuickSave,
[quickSave],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
bool isAutoFinish() => (super.noSuchMethod(
Invocation.method(
#isAutoFinish,
[],
),
returnValue: false,
returnValueForMissingStub: false,
) as bool);
@override
_i4.Future<void> setAutoFinish(bool? autoFinish) => (super.noSuchMethod(
Invocation.method(
#setAutoFinish,
[autoFinish],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
bool isMinimizeToTray() => (super.noSuchMethod(
Invocation.method(
#isMinimizeToTray,
[],
),
returnValue: false,
returnValueForMissingStub: false,
) as bool);
@override
_i4.Future<void> setMinimizeToTray(bool? minimizeToTray) =>
(super.noSuchMethod(
Invocation.method(
#setMinimizeToTray,
[minimizeToTray],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
bool isLaunchAtStartup() => (super.noSuchMethod(
Invocation.method(
#isLaunchAtStartup,
[],
),
returnValue: false,
returnValueForMissingStub: false,
) as bool);
@override
_i4.Future<void> setLaunchAtStartup(bool? launchAtStartup) =>
(super.noSuchMethod(
Invocation.method(
#setLaunchAtStartup,
[launchAtStartup],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
bool isAutoStartLaunchMinimized() => (super.noSuchMethod(
Invocation.method(
#isAutoStartLaunchMinimized,
[],
),
returnValue: false,
returnValueForMissingStub: false,
) as bool);
@override
_i4.Future<void> setAutoStartLaunchMinimized(bool? launchMinimized) =>
(super.noSuchMethod(
Invocation.method(
#setAutoStartLaunchMinimized,
[launchMinimized],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
bool isHttps() => (super.noSuchMethod(
Invocation.method(
#isHttps,
[],
),
returnValue: false,
returnValueForMissingStub: false,
) as bool);
@override
_i4.Future<void> setHttps(bool? https) => (super.noSuchMethod(
Invocation.method(
#setHttps,
[https],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
_i11.SendMode getSendMode() => (super.noSuchMethod(
Invocation.method(
#getSendMode,
[],
),
returnValue: _i11.SendMode.single,
returnValueForMissingStub: _i11.SendMode.single,
) as _i11.SendMode);
@override
_i4.Future<void> setSendMode(_i11.SendMode? mode) => (super.noSuchMethod(
Invocation.method(
#setSendMode,
[mode],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
_i4.Future<void> setWindowOffsetX(double? x) => (super.noSuchMethod(
Invocation.method(
#setWindowOffsetX,
[x],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
_i4.Future<void> setWindowOffsetY(double? y) => (super.noSuchMethod(
Invocation.method(
#setWindowOffsetY,
[y],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
_i4.Future<void> setWindowHeight(double? height) => (super.noSuchMethod(
Invocation.method(
#setWindowHeight,
[height],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
_i4.Future<void> setWindowWidth(double? width) => (super.noSuchMethod(
Invocation.method(
#setWindowWidth,
[width],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
Map<String, _i12.OffsetBase?> getWindowLastDimensions() =>
(super.noSuchMethod(
Invocation.method(
#getWindowLastDimensions,
[],
),
returnValue: <String, _i12.OffsetBase?>{},
returnValueForMissingStub: <String, _i12.OffsetBase?>{},
) as Map<String, _i12.OffsetBase?>);
@override
_i4.Future<void> setSaveWindowPlacement(bool? savePlacement) =>
(super.noSuchMethod(
Invocation.method(
#setSaveWindowPlacement,
[savePlacement],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
bool getSaveWindowPlacement() => (super.noSuchMethod(
Invocation.method(
#getSaveWindowPlacement,
[],
),
returnValue: false,
returnValueForMissingStub: false,
) as bool);
@override
_i4.Future<void> setEnableAnimations(bool? enableAnimations) =>
(super.noSuchMethod(
Invocation.method(
#setEnableAnimations,
[enableAnimations],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
bool getEnableAnimations() => (super.noSuchMethod(
Invocation.method(
#getEnableAnimations,
[],
),
returnValue: false,
returnValueForMissingStub: false,
) as bool);
@override
_i4.Future<void> setDeviceType(_i13.DeviceType? deviceType) =>
(super.noSuchMethod(
Invocation.method(
#setDeviceType,
[deviceType],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
_i4.Future<void> setDeviceModel(String? deviceModel) => (super.noSuchMethod(
Invocation.method(
#setDeviceModel,
[deviceModel],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
@override
_i4.Future<void> clear() => (super.noSuchMethod(
Invocation.method(
#clear,
[],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
}
/// A class which mocks [SharedPreferences].
///
/// See the documentation for Mockito's code generation for more information.
class MockSharedPreferences extends _i1.Mock implements _i14.SharedPreferences {
@override
Set<String> getKeys() => (super.noSuchMethod(
Invocation.method(
#getKeys,
[],
),
returnValue: <String>{},
returnValueForMissingStub: <String>{},
) as Set<String>);
@override
Object? get(String? key) => (super.noSuchMethod(
Invocation.method(
#get,
[key],
),
returnValueForMissingStub: null,
) as Object?);
@override
bool? getBool(String? key) => (super.noSuchMethod(
Invocation.method(
#getBool,
[key],
),
returnValueForMissingStub: null,
) as bool?);
@override
int? getInt(String? key) => (super.noSuchMethod(
Invocation.method(
#getInt,
[key],
),
returnValueForMissingStub: null,
) as int?);
@override
double? getDouble(String? key) => (super.noSuchMethod(
Invocation.method(
#getDouble,
[key],
),
returnValueForMissingStub: null,
) as double?);
@override
String? getString(String? key) => (super.noSuchMethod(
Invocation.method(
#getString,
[key],
),
returnValueForMissingStub: null,
) as String?);
@override
bool containsKey(String? key) => (super.noSuchMethod(
Invocation.method(
#containsKey,
[key],
),
returnValue: false,
returnValueForMissingStub: false,
) as bool);
@override
List<String>? getStringList(String? key) => (super.noSuchMethod(
Invocation.method(
#getStringList,
[key],
),
returnValueForMissingStub: null,
) as List<String>?);
@override
_i4.Future<bool> setBool(
String? key,
bool? value,
) =>
(super.noSuchMethod(
Invocation.method(
#setBool,
[
key,
value,
],
),
returnValue: _i4.Future<bool>.value(false),
returnValueForMissingStub: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);
@override
_i4.Future<bool> setInt(
String? key,
int? value,
) =>
(super.noSuchMethod(
Invocation.method(
#setInt,
[
key,
value,
],
),
returnValue: _i4.Future<bool>.value(false),
returnValueForMissingStub: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);
@override
_i4.Future<bool> setDouble(
String? key,
double? value,
) =>
(super.noSuchMethod(
Invocation.method(
#setDouble,
[
key,
value,
],
),
returnValue: _i4.Future<bool>.value(false),
returnValueForMissingStub: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);
@override
_i4.Future<bool> setString(
String? key,
String? value,
) =>
(super.noSuchMethod(
Invocation.method(
#setString,
[
key,
value,
],
),
returnValue: _i4.Future<bool>.value(false),
returnValueForMissingStub: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);
@override
_i4.Future<bool> setStringList(
String? key,
List<String>? value,
) =>
(super.noSuchMethod(
Invocation.method(
#setStringList,
[
key,
value,
],
),
returnValue: _i4.Future<bool>.value(false),
returnValueForMissingStub: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);
@override
_i4.Future<bool> remove(String? key) => (super.noSuchMethod(
Invocation.method(
#remove,
[key],
),
returnValue: _i4.Future<bool>.value(false),
returnValueForMissingStub: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);
@override
_i4.Future<bool> commit() => (super.noSuchMethod(
Invocation.method(
#commit,
[],
),
returnValue: _i4.Future<bool>.value(false),
returnValueForMissingStub: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);
@override
_i4.Future<bool> clear() => (super.noSuchMethod(
Invocation.method(
#clear,
[],
),
returnValue: _i4.Future<bool>.value(false),
returnValueForMissingStub: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);
@override
_i4.Future<void> reload() => (super.noSuchMethod(
Invocation.method(
#reload,
[],
),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);
}
@@ -0,0 +1,114 @@
import 'package:localsend_app/model/persistence/favorite_device.dart';
import 'package:localsend_app/provider/favorites_provider.dart';
import 'package:mockito/mockito.dart';
import 'package:refena_flutter/refena_flutter.dart';
import 'package:test/test.dart';
import '../../mocks.mocks.dart';
void main() {
late MockPersistenceService persistenceService;
setUp(() {
persistenceService = MockPersistenceService();
});
test('Should add a favorite device', () async {
final service = ReduxNotifier.test(
redux: FavoritesService(persistenceService),
);
expect(service.state, []);
final device = _createDevice('1');
await service.dispatchAsync(AddFavoriteAction(device));
expect(service.state, [device]);
verify(persistenceService.setFavorites([device]));
});
test('Should update a favorite device', () async {
final initialDevice = _createDevice('1', alias: 'A');
final service = ReduxNotifier.test(
redux: FavoritesService(persistenceService),
initialState: [initialDevice],
);
// Sanity check
expect(service.state, [initialDevice]);
expect(service.state.first.alias, 'A');
final updatedDevice = _createDevice('1', alias: 'B');
await service.dispatchAsync(UpdateFavoriteAction(updatedDevice));
expect(service.state, [updatedDevice]);
expect(service.state.first.alias, 'B');
verify(persistenceService.setFavorites([updatedDevice]));
});
test('Should not update a favorite device if unknown id', () async {
final initialDevice = _createDevice('1', alias: 'A');
final service = ReduxNotifier.test(
redux: FavoritesService(persistenceService),
initialState: [initialDevice],
);
// Sanity check
expect(service.state, [initialDevice]);
expect(service.state.first.alias, 'A');
final updatedDevice = _createDevice('2', alias: 'B');
await service.dispatchAsync(UpdateFavoriteAction(updatedDevice));
expect(service.state, [initialDevice]);
expect(service.state.first.alias, 'A');
verifyNever(persistenceService.setFavorites(any));
});
test('Should delete favorite device', () async {
final initialDevice = _createDevice('1', fingerprint: '111');
final service = ReduxNotifier.test(
redux: FavoritesService(persistenceService),
initialState: [initialDevice],
);
// Sanity check
expect(service.state, [initialDevice]);
await service.dispatchAsync(RemoveFavoriteAction(deviceFingerprint: '111'));
expect(service.state, []);
verify(persistenceService.setFavorites([]));
});
test('Should not delete favorite device if unknown fingerprint', () async {
final initialDevice = _createDevice('1', fingerprint: '111');
final service = ReduxNotifier.test(
redux: FavoritesService(persistenceService),
initialState: [initialDevice],
);
// Sanity check
expect(service.state, [initialDevice]);
await service.dispatchAsync(RemoveFavoriteAction(deviceFingerprint: '222'));
expect(service.state, [initialDevice]);
verifyNever(persistenceService.setFavorites(any));
});
}
FavoriteDevice _createDevice(
String id, {
String fingerprint = '123',
String alias = 'A',
}) {
return FavoriteDevice(
id: id,
fingerprint: fingerprint,
ip: '1.2.3.4',
port: 123,
alias: alias,
);
}
@@ -5,31 +5,31 @@ import 'package:test/test.dart';
void main() {
test('Should add a device', () {
final notifier = ReduxNotifier.test(
redux: LastDevicesNotifier(),
final service = ReduxNotifier.test(
redux: LastDevicesService(),
);
expect(notifier.state, []);
expect(service.state, []);
final device = _createDevice('123.123');
notifier.dispatch(AddLastDeviceAction(device));
service.dispatch(AddLastDeviceAction(device));
expect(notifier.state, [device]);
expect(service.state, [device]);
});
test('Should remove the 5th device', () {
final notifier = ReduxNotifier.test(
redux: LastDevicesNotifier(),
final service = ReduxNotifier.test(
redux: LastDevicesService(),
);
notifier.dispatch(AddLastDeviceAction(_createDevice('1')));
notifier.dispatch(AddLastDeviceAction(_createDevice('2')));
notifier.dispatch(AddLastDeviceAction(_createDevice('3')));
notifier.dispatch(AddLastDeviceAction(_createDevice('4')));
notifier.dispatch(AddLastDeviceAction(_createDevice('5')));
service.dispatch(AddLastDeviceAction(_createDevice('1')));
service.dispatch(AddLastDeviceAction(_createDevice('2')));
service.dispatch(AddLastDeviceAction(_createDevice('3')));
service.dispatch(AddLastDeviceAction(_createDevice('4')));
service.dispatch(AddLastDeviceAction(_createDevice('5')));
expect(notifier.state.length, 5);
expect(notifier.state, [
expect(service.state.length, 5);
expect(service.state, [
_createDevice('5'),
_createDevice('4'),
_createDevice('3'),
@@ -37,10 +37,10 @@ void main() {
_createDevice('1'),
]);
notifier.dispatch(AddLastDeviceAction(_createDevice('6')));
service.dispatch(AddLastDeviceAction(_createDevice('6')));
expect(notifier.state.length, 5);
expect(notifier.state, [
expect(service.state.length, 5);
expect(service.state, [
_createDevice('6'),
_createDevice('5'),
_createDevice('4'),
@@ -0,0 +1,171 @@
import 'package:localsend_app/model/file_type.dart';
import 'package:localsend_app/model/persistence/receive_history_entry.dart';
import 'package:localsend_app/provider/receive_history_provider.dart';
import 'package:mockito/mockito.dart';
import 'package:refena_flutter/refena_flutter.dart';
import 'package:test/test.dart';
import '../../mocks.mocks.dart';
void main() {
late MockPersistenceService persistenceService;
setUp(() {
persistenceService = MockPersistenceService();
when(persistenceService.isSaveToHistory()).thenReturn(true);
});
test('Should add an entry', () async {
final service = ReduxNotifier.test(
redux: ReceiveHistoryService(persistenceService),
);
final entry = _createEntry('1');
await service.dispatchAsync(AddHistoryEntryAction(
entryId: entry.id,
fileName: entry.fileName,
fileType: entry.fileType,
path: entry.path,
savedToGallery: entry.savedToGallery,
fileSize: entry.fileSize,
senderAlias: entry.senderAlias,
timestamp: entry.timestamp,
));
expect(service.state, [entry]);
verify(persistenceService.setReceiveHistory([entry]));
});
test('Should not add an entry if disabled', () async {
when(persistenceService.isSaveToHistory()).thenReturn(false);
final service = ReduxNotifier.test(
redux: ReceiveHistoryService(persistenceService),
);
final entry = _createEntry('1');
await service.dispatchAsync(AddHistoryEntryAction(
entryId: entry.id,
fileName: entry.fileName,
fileType: entry.fileType,
path: entry.path,
savedToGallery: entry.savedToGallery,
fileSize: entry.fileSize,
senderAlias: entry.senderAlias,
timestamp: entry.timestamp,
));
expect(service.state, []);
verifyNever(persistenceService.setReceiveHistory(any));
});
test('Should remove the 200th entry when adding another', () async {
final service = ReduxNotifier.test(
redux: ReceiveHistoryService(persistenceService),
initialState: List.generate(200, (index) => _createEntry(index.toString())),
);
expect(service.state.length, 200);
expect(service.state.first, _createEntry('0'));
expect(service.state.last, _createEntry('199'));
final entry = _createEntry('AAA');
await service.dispatchAsync(AddHistoryEntryAction(
entryId: entry.id,
fileName: entry.fileName,
fileType: entry.fileType,
path: entry.path,
savedToGallery: entry.savedToGallery,
fileSize: entry.fileSize,
senderAlias: entry.senderAlias,
timestamp: entry.timestamp,
));
expect(service.state.length, 200);
expect(service.state.first, entry);
expect(service.state[1], _createEntry('0'));
expect(service.state.last, _createEntry('198'));
});
test('Should remove an entry', () async {
final service = ReduxNotifier.test(
redux: ReceiveHistoryService(persistenceService),
initialState: [
_createEntry('1'),
_createEntry('2'),
_createEntry('3'),
],
);
expect(service.state.length, 3);
await service.dispatchAsync(RemoveHistoryEntryAction('2'));
expect(service.state.length, 2);
expect(service.state, [
_createEntry('1'),
_createEntry('3'),
]);
verify(persistenceService.setReceiveHistory([
_createEntry('1'),
_createEntry('3'),
]));
});
test('Should not remove an entry if not found', () async {
final service = ReduxNotifier.test(
redux: ReceiveHistoryService(persistenceService),
initialState: [
_createEntry('1'),
_createEntry('2'),
_createEntry('3'),
],
);
expect(service.state.length, 3);
await service.dispatchAsync(RemoveHistoryEntryAction('4'));
expect(service.state.length, 3);
expect(service.state, [
_createEntry('1'),
_createEntry('2'),
_createEntry('3'),
]);
verifyNever(persistenceService.setReceiveHistory(any));
});
test('Should remove all entries', () async {
final service = ReduxNotifier.test(
redux: ReceiveHistoryService(persistenceService),
initialState: [
_createEntry('1'),
_createEntry('2'),
_createEntry('3'),
],
);
expect(service.state.length, 3);
await service.dispatchAsync(RemoveAllHistoryEntriesAction());
expect(service.state.length, 0);
verify(persistenceService.setReceiveHistory([]));
});
}
ReceiveHistoryEntry _createEntry(String id) {
return ReceiveHistoryEntry(
id: id,
fileName: 'fileName',
fileType: FileType.image,
path: 'path',
savedToGallery: true,
fileSize: 123,
senderAlias: 'senderAlias',
timestamp: DateTime(2021, 1, 1),
);
}