Test case for LsDirBloc

This commit is contained in:
Ming Ming 2021-08-17 03:05:00 +08:00
parent e9659509a8
commit f430e8f3cd
6 changed files with 252 additions and 6 deletions

View file

@ -1,11 +1,12 @@
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/entity/file/data_source.dart';
import 'package:nc_photos/use_case/ls.dart'; import 'package:nc_photos/use_case/ls.dart';
class LsDirBlocItem { class LsDirBlocItem with EquatableMixin {
LsDirBlocItem(this.file, this.children); LsDirBlocItem(this.file, this.children);
@override @override
@ -32,6 +33,12 @@ class LsDirBlocItem {
return product; return product;
} }
@override
get props => [
file,
children,
];
final File file; final File file;
/// Child directories under this directory /// Child directories under this directory
@ -77,18 +84,25 @@ class LsDirBlocQuery extends LsDirBlocEvent {
final int depth; final int depth;
} }
abstract class LsDirBlocState { abstract class LsDirBlocState with EquatableMixin {
const LsDirBlocState(this.account, this.root, this.items); const LsDirBlocState(this.account, this.root, this.items);
@override @override
toString() { toString() {
return "$runtimeType {" return "$runtimeType {"
"account: $account, " "account: $account, "
"root: ${root.path}" "root: ${root.path}, "
"items: List {length: ${items.length}}, " "items: List {length: ${items.length}}, "
"}"; "}";
} }
@override
get props => [
account,
root,
items,
];
final Account? account; final Account? account;
final File root; final File root;
final List<LsDirBlocItem> items; final List<LsDirBlocItem> items;
@ -121,12 +135,20 @@ class LsDirBlocFailure extends LsDirBlocState {
"}"; "}";
} }
@override
get props => [
...super.props,
exception,
];
final dynamic exception; final dynamic exception;
} }
/// A bloc that return all directories under a dir recursively /// A bloc that return all directories under a dir recursively
class LsDirBloc extends Bloc<LsDirBlocEvent, LsDirBlocState> { class LsDirBloc extends Bloc<LsDirBlocEvent, LsDirBlocState> {
LsDirBloc() : super(LsDirBlocInit()); LsDirBloc({
this.fileRepo = const FileRepo(const FileWebdavDataSource()),
}) : super(LsDirBlocInit());
@override @override
mapEventToState(LsDirBlocEvent event) async* { mapEventToState(LsDirBlocEvent event) async* {
@ -150,7 +172,7 @@ class LsDirBloc extends Bloc<LsDirBlocEvent, LsDirBlocState> {
final product = <LsDirBlocItem>[]; final product = <LsDirBlocItem>[];
var files = _cache[ev.root.path]; var files = _cache[ev.root.path];
if (files == null) { if (files == null) {
files = (await Ls(FileRepo(FileWebdavDataSource()))(ev.account, ev.root)) files = (await Ls(fileRepo)(ev.account, ev.root))
.where((f) => f.isCollection ?? false) .where((f) => f.isCollection ?? false)
.toList(); .toList();
_cache[ev.root.path] = files; _cache[ev.root.path] = files;
@ -165,6 +187,8 @@ class LsDirBloc extends Bloc<LsDirBlocEvent, LsDirBlocState> {
return product; return product;
} }
final FileRepo fileRepo;
final _cache = <String, List<File>>{}; final _cache = <String, List<File>>{};
static final _log = Logger("bloc.ls_dir.LsDirBloc"); static final _log = Logger("bloc.ls_dir.LsDirBloc");

View file

@ -456,7 +456,7 @@ extension FileExtension on File {
} }
class FileRepo { class FileRepo {
FileRepo(this.dataSrc); const FileRepo(this.dataSrc);
/// See [FileDataSource.list] /// See [FileDataSource.list]
Future<List<File>> list(Account account, File root) => Future<List<File>> list(Account account, File root) =>

View file

@ -22,6 +22,8 @@ import 'package:uuid/uuid.dart';
import 'package:xml/xml.dart'; import 'package:xml/xml.dart';
class FileWebdavDataSource implements FileDataSource { class FileWebdavDataSource implements FileDataSource {
const FileWebdavDataSource();
@override @override
list( list(
Account account, Account account,

View file

@ -50,6 +50,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "7.0.0" version: "7.0.0"
bloc_test:
dependency: "direct dev"
description:
name: bloc_test
url: "https://pub.dartlang.org"
source: hosted
version: "8.1.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -412,6 +419,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.0"
mocktail:
dependency: transitive
description:
name: mocktail
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
nested: nested:
dependency: transitive dependency: transitive
description: description:

View file

@ -79,6 +79,7 @@ dependencies:
dev_dependencies: dev_dependencies:
test: any test: any
bloc_test: any
# flutter_test: # flutter_test:
# sdk: flutter # sdk: flutter
# integration_test: # integration_test:

205
test/bloc/ls_dir_test.dart Normal file
View file

@ -0,0 +1,205 @@
import 'dart:typed_data';
import 'package:bloc_test/bloc_test.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/bloc/ls_dir.dart';
import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/or_null.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
void main() {
final _buildBloc = () => LsDirBloc(fileRepo: _MockFileRepo());
final _buildAccount =
() => Account("http", "example.com", "admin", "pass", [""]);
group("ListDir", () {
group("LsDirBlocQuery", () {
test("initial state", () {
final bloc = _buildBloc();
expect(bloc.state.account, null);
expect(bloc.state.root, File(path: ""));
expect(bloc.state.items, []);
});
blocTest(
"inital",
build: _buildBloc,
expect: () => [],
);
blocTest<LsDirBloc, LsDirBlocState>(
"query 1 subdir",
build: _buildBloc,
act: (bloc) => bloc.add(LsDirBlocQuery(
_buildAccount(), File(path: "remote.php/dav/files/admin"))),
expect: () => [
LsDirBlocLoading(
_buildAccount(), File(path: "remote.php/dav/files/admin"), []),
LsDirBlocSuccess(
_buildAccount(), File(path: "remote.php/dav/files/admin"), [
LsDirBlocItem(
File(
path: "remote.php/dav/files/admin/d1",
isCollection: true,
),
null,
),
]),
],
);
blocTest<LsDirBloc, LsDirBlocState>(
"query n subdir",
build: _buildBloc,
act: (bloc) => bloc.add(LsDirBlocQuery(
_buildAccount(), File(path: "remote.php/dav/files/admin/d1"))),
expect: () => [
LsDirBlocLoading(
_buildAccount(), File(path: "remote.php/dav/files/admin/d1"), []),
LsDirBlocSuccess(
_buildAccount(), File(path: "remote.php/dav/files/admin/d1"), [
LsDirBlocItem(
File(
path: "remote.php/dav/files/admin/d1/d2-1",
isCollection: true,
),
null,
),
LsDirBlocItem(
File(
path: "remote.php/dav/files/admin/d1/d2-2",
isCollection: true,
),
null,
),
]),
],
);
blocTest<LsDirBloc, LsDirBlocState>(
"query 0 subdir",
build: _buildBloc,
act: (bloc) => bloc.add(LsDirBlocQuery(
_buildAccount(), File(path: "remote.php/dav/files/admin/d1/d2-2"))),
expect: () => [
LsDirBlocLoading(_buildAccount(),
File(path: "remote.php/dav/files/admin/d1/d2-2"), []),
LsDirBlocSuccess(_buildAccount(),
File(path: "remote.php/dav/files/admin/d1/d2-2"), []),
],
);
blocTest<LsDirBloc, LsDirBlocState>(
"query depth 2",
build: _buildBloc,
act: (bloc) => bloc.add(LsDirBlocQuery(
_buildAccount(), File(path: "remote.php/dav/files/admin"),
depth: 2)),
expect: () => [
LsDirBlocLoading(
_buildAccount(), File(path: "remote.php/dav/files/admin"), []),
LsDirBlocSuccess(
_buildAccount(), File(path: "remote.php/dav/files/admin"), [
LsDirBlocItem(
File(
path: "remote.php/dav/files/admin/d1",
isCollection: true,
),
[
LsDirBlocItem(
File(
path: "remote.php/dav/files/admin/d1/d2-1",
isCollection: true,
),
null,
),
LsDirBlocItem(
File(
path: "remote.php/dav/files/admin/d1/d2-2",
isCollection: true,
),
null,
),
],
),
]),
],
);
});
});
}
class _MockFileRepo implements FileRepo {
@override
Future<void> copy(Object account, File f, String destination,
{bool? shouldOverwrite}) {
throw UnimplementedError();
}
@override
Future<void> createDir(Account account, String path) {
throw UnimplementedError();
}
@override
FileDataSource get dataSrc => throw UnimplementedError();
@override
Future<Uint8List> getBinary(Account account, File file) {
throw UnimplementedError();
}
@override
Future<List<File>> list(Account account, File root) async {
await Future.delayed(const Duration(seconds: 1));
return [
File(
path: "remote.php/dav/files/admin/test1.jpg",
),
File(
path: "remote.php/dav/files/admin/d1",
isCollection: true,
),
File(
path: "remote.php/dav/files/admin/d1/test2.jpg",
),
File(
path: "remote.php/dav/files/admin/d1/d2-1",
isCollection: true,
),
File(
path: "remote.php/dav/files/admin/d1/d2-2",
isCollection: true,
),
File(
path: "remote.php/dav/files/admin/d1/d2-1/d3",
isCollection: true,
),
].where((element) => path.dirname(element.path) == root.path).toList();
}
@override
Future<void> move(Account account, File f, String destination,
{bool? shouldOverwrite}) {
throw UnimplementedError();
}
@override
Future<void> putBinary(Account account, String path, Uint8List content) {
throw UnimplementedError();
}
@override
Future<void> remove(Account account, File file) {
throw UnimplementedError();
}
@override
Future<void> updateProperty(Account account, File file,
{OrNull<Metadata>? metadata,
OrNull<bool>? isArchived,
OrNull<DateTime>? overrideDateTime}) {
throw UnimplementedError();
}
}