Skip to content

Commit

Permalink
Merged: Add tests for the moving operation when the destination repo …
Browse files Browse the repository at this point in the history
…is blind/locked or read only
  • Loading branch information
J-Pabon committed Nov 19, 2024
2 parents 819aa89 + 239be92 commit 473a5c5
Show file tree
Hide file tree
Showing 4 changed files with 292 additions and 57 deletions.
1 change: 1 addition & 0 deletions lib/app/widgets/bars/repositories_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class RepositoriesBar extends StatelessWidget
}

Widget _buildLockButtonContent(RepoCubit? repoCubit) => IconButton(
key: ValueKey('lock_repo_icon'),
icon: Icon(
Fields.accessModeIcon(repoCubit?.accessMode ?? AccessMode.blind)),
iconSize: Dimensions.sizeIconSmall,
Expand Down
111 changes: 54 additions & 57 deletions lib/app/widgets/dialogs/move_entry_bottom_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class _MoveEntryDialogState extends State<MoveEntryDialog> {
builder: (context, state) {
final aspectRatio = _getButtonAspectRatio(widgetSize);
return Fields.dialogActions(
buttons: _actions(context, isRepoList, aspectRatio),
buttons: _actions(context, state, isRepoList, aspectRatio),
padding: const EdgeInsetsDirectional.only(top: 20.0),
mainAxisAlignment: MainAxisAlignment.end,
);
Expand All @@ -120,65 +120,62 @@ class _MoveEntryDialogState extends State<MoveEntryDialog> {

List<Widget> _actions(
BuildContext context,
NavigationState state,
bool isRepoList,
double aspectRatio,
) =>
[
NegativeButton(
buttonsAspectRatio: aspectRatio,
buttonConstrains: Dimensions.sizeConstrainsBottomDialogAction,
text: S.current.actionCancel,
onPressed: () {
widget.onUpdateBottomSheet(BottomSheetType.gone, 0.0, '');
widget.onCancel();
},
),
BlocBuilder<NavigationCubit, NavigationState>(
bloc: navigationCubit,
builder: (context, state) {
final currentRepoAccessMode =
widget.reposCubit.currentRepo?.accessMode;
final isCurrentRepoWriteMode =
currentRepoAccessMode == AccessMode.write;

final canMove = state.isFolder
? _canMove(
originRepoLocation: originRepoCubit.location,
originPath: repo_path.dirname(entryPath),
destinationRepoLocation: state.repoLocation,
destinationPath: state.path,
isRepoList: isRepoList,
isCurrentRepoWriteMode: isCurrentRepoWriteMode,
)
: false;
return PositiveButton(
buttonsAspectRatio: aspectRatio,
buttonConstrains: Dimensions.sizeConstrainsBottomDialogAction,
text: S.current.actionMove,
onPressed: canMove
? () async {
await Dialogs.executeFutureWithLoadingDialog(
null,
widget.onMoveEntry(),
).then(
(_) {
widget.onUpdateBottomSheet(
BottomSheetType.gone,
0.0,
'',
);
widget.onCancel();
},
);
}
: null,
);
},
),
) {
final currentRepoAccessMode = widget.reposCubit.currentRepo?.accessMode;
final isCurrentRepoWriteMode = currentRepoAccessMode == AccessMode.write;

final canMove = state.isFolder
? _canMove(
originRepoLocation: originRepoCubit.location,
originPath: repo_path.dirname(entryPath),
destinationRepoLocation:
widget.reposCubit.currentRepo?.cubit?.location ??
state.repoLocation,
destinationPath: state.path,
isRepoList: isRepoList,
isCurrentRepoWriteMode: isCurrentRepoWriteMode,
)
: false;

/// If the entry can't be moved (the user selected the same entry/path, for example)
/// Then null is used instead of the function, which disable the button.
];
return [
NegativeButton(
buttonsAspectRatio: aspectRatio,
buttonConstrains: Dimensions.sizeConstrainsBottomDialogAction,
text: S.current.actionCancel,
onPressed: () {
widget.onUpdateBottomSheet(BottomSheetType.gone, 0.0, '');
widget.onCancel();
},
),
PositiveButton(
key: ValueKey('move_entry'),
buttonsAspectRatio: aspectRatio,
buttonConstrains: Dimensions.sizeConstrainsBottomDialogAction,
text: S.current.actionMove,
onPressed: canMove
? () async {
widget.onUpdateBottomSheet(
BottomSheetType.gone,
0.0,
'',
);
widget.onCancel();

await Dialogs.executeFutureWithLoadingDialog(
null,
widget.onMoveEntry(),
);
}
: null,
)

/// If the entry can't be moved (the user selected the same entry/path, for example)
/// Then null is used instead of the function, which disable the button.
];
}

bool _canMove({
required RepoLocation originRepoLocation,
Expand Down
1 change: 1 addition & 0 deletions lib/app/widgets/items/list_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ class _VerticalDotsButton extends StatelessWidget {

@override
Widget build(BuildContext context) => IconButton(
key: ValueKey('file_vert'),
icon: const Icon(
Icons.more_vert_rounded,
size: Dimensions.sizeIconSmall,
Expand Down
236 changes: 236 additions & 0 deletions test/widget/move_entry_repo_no_write_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:golden_toolkit/golden_toolkit.dart';
import 'package:ouisync_app/app/cubits/cubits.dart' show RepoCubit;
import 'package:ouisync_app/app/models/models.dart'
show LocalSecretMode, LocalSecretKeyAndSalt, RepoEntry, RepoLocation;
import 'package:ouisync/ouisync.dart' show AccessMode, File, Repository;
import 'package:ouisync_app/app/utils/share_token.dart';

import '../utils.dart' show BlocBaseExtension, TestDependencies, testApp;

void main() {
late TestDependencies deps;

final String originRepoName = 'origin';
final String lockedRepoName = 'locked repo';
final String readRepoName = 'read repo';

final String readTokenString =
'https://ouisync.net/r#AwEgOdW98iaOedPg8CG3J7szV_-lMFH9OSgBSRz6C6w3CBcgx5QxWXk3jhFd8rx1zObVJZd0OVc3EQD_YuRReKDLE5M?name=uno';

late Repository originRepo;
late RepoEntry lockedRepoEntry;

setUp(() async {
deps = await TestDependencies.create();

final reposDir = await deps.reposCubit.settings.getDefaultRepositoriesDir();

final originRepoLocation = RepoLocation.fromParts(
dir: reposDir,
name: originRepoName,
);

final lockedRepoLocation = RepoLocation.fromParts(
dir: reposDir,
name: lockedRepoName,
);

final readRepoLocation = RepoLocation.fromParts(
dir: reposDir,
name: readRepoName,
);

await deps.reposCubit.createRepository(
location: originRepoLocation,
setLocalSecret: LocalSecretKeyAndSalt.random(),
localSecretMode: LocalSecretMode.randomStored,
);

lockedRepoEntry = await deps.reposCubit.createRepository(
location: lockedRepoLocation,
setLocalSecret: LocalSecretKeyAndSalt.random(),
localSecretMode: LocalSecretMode.randomStored,
);

await lockedRepoEntry.cubit?.lock();

final readTokenResult = await parseShareToken(
deps.reposCubit,
readTokenString,
);
final readToken = (readTokenResult as ShareTokenValid);
await deps.reposCubit.createRepository(
location: readRepoLocation,
setLocalSecret: LocalSecretKeyAndSalt.random(),
localSecretMode: LocalSecretMode.randomStored,
token: readToken.value,
);

originRepo = await Repository.open(
deps.session,
store: originRepoLocation.path,
);

final newFile = await File.create(originRepo, '/file.txt');
await newFile.write(0, 'Hello world!'.codeUnits);
await newFile.close();
});

tearDown(() async {
await lockedRepoEntry.close();
await originRepo.close();
await deps.dispose();
});

testWidgets(
'move file to a blind/locked repo and confirm that MOVE button is disabled',
(tester) => tester.runAsync(
() async {
await loadAppFonts();

await tester.pumpWidget(testApp(deps.createMainPage()));
await tester.pumpAndSettle();

expect(find.text(originRepoName), findsOne);
expect(find.text(lockedRepoName), findsOne);
expect(find.text(readRepoName), findsOne);

final originRepoCubit = deps.reposCubit.repos
.firstWhere((r) => r.name == originRepoName)
.cubit!;

await tester.tap(find.text(originRepoName));
await _waitForNavigationIntoRepoToEnd(deps, tester, originRepoCubit);

final fileVert = find.byKey(ValueKey('file_vert'));
expect(fileVert, findsOne);

await tester.tap(fileVert);
await tester.pumpAndSettle();

final moveListTile = find.widgetWithText(ListTile, 'Move');
expect(moveListTile, findsOne);

await tester.tap(moveListTile);
await tester.pumpAndSettle();

final backButton = find.widgetWithIcon(
IconButton,
Icons.arrow_back_rounded,
);
expect(backButton, findsOne);

await tester.tap(backButton);
await tester.pumpAndSettle();

final lockedRepoCubit = deps.reposCubit.repos
.firstWhere((r) => r.name == lockedRepoName)
.cubit!;

await tester.tap(find.text(lockedRepoName));
await _waitForNavigationIntoRepoToEnd(
deps,
tester,
lockedRepoCubit,
);

final currentRepoEntry = deps.reposCubit.currentRepo;
expect(currentRepoEntry?.accessMode, equals(AccessMode.blind));

final moveButton = find.descendant(
of: find.byKey(ValueKey('move_entry')),
matching: find.byWidgetPredicate(
(widget) => widget is RawMaterialButton,
),
);
expect(moveButton, findsOne);
expect(tester.widget<RawMaterialButton>(moveButton).enabled, false);
},
),
);

testWidgets(
'move file to a read repo and confirm that MOVE button is disabled',
(tester) => tester.runAsync(
() async {
await loadAppFonts();

await tester.pumpWidget(testApp(deps.createMainPage()));
await tester.pumpAndSettle();

expect(find.text(originRepoName), findsOne);
expect(find.text(lockedRepoName), findsOne);
expect(find.text(readRepoName), findsOne);

final originRepoCubit = deps.reposCubit.repos
.firstWhere((r) => r.name == originRepoName)
.cubit!;

await tester.tap(find.text(originRepoName));
await _waitForNavigationIntoRepoToEnd(deps, tester, originRepoCubit);

final fileVert = find.byKey(ValueKey('file_vert'));
expect(fileVert, findsOne);

await tester.tap(fileVert);
await tester.pumpAndSettle();

final moveListTile = find.widgetWithText(ListTile, 'Move');
expect(moveListTile, findsOne);

await tester.tap(moveListTile);
await tester.pumpAndSettle();

final backButton = find.widgetWithIcon(
IconButton,
Icons.arrow_back_rounded,
);
expect(backButton, findsOne);

await tester.tap(backButton);
await tester.pumpAndSettle();

final readRepoCubit = deps.reposCubit.repos
.firstWhere((r) => r.name == readRepoName)
.cubit!;

await tester.tap(find.text(readRepoName));
await _waitForNavigationIntoRepoToEnd(
deps,
tester,
readRepoCubit,
);

final currentRepoEntry = deps.reposCubit.currentRepo;
expect(currentRepoEntry?.accessMode, equals(AccessMode.read));

final moveButton = find.descendant(
of: find.byKey(ValueKey('move_entry')),
matching: find.byWidgetPredicate(
(widget) => widget is RawMaterialButton,
),
);
expect(moveButton, findsOne);
expect(tester.widget<RawMaterialButton>(moveButton).enabled, false);
},
),
);
}

Future<void> _waitForNavigationIntoRepoToEnd(
TestDependencies deps,
WidgetTester tester,
RepoCubit repo,
) async {
await deps.reposCubit.waitUntil((_) =>
!deps.reposCubit.isLoading &&
deps.reposCubit.currentRepo?.name == repo.name);
await tester.pump();

await deps.reposCubit.currentRepo?.cubit?.waitUntil(
(_) => deps.reposCubit.currentRepo?.cubit?.state.isLoading == false);
await tester.pumpAndSettle();
await tester.pump(Duration(seconds: 1));
}

0 comments on commit 473a5c5

Please sign in to comment.