tests: tests for dart repositories
This commit is contained in:
parent
bdfb08f092
commit
d4bf238f50
@ -35,4 +35,9 @@ class ProjectRepositoryImpl implements ProjectRepository {
|
|||||||
TaskEither<IError, List<Project>> findAll() {
|
TaskEither<IError, List<Project>> findAll() {
|
||||||
return database.projects.findAll();
|
return database.projects.findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, List<Project>> findByUserId(String userId) {
|
||||||
|
return database.projects.findByUserId(userId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ class User with _$User {
|
|||||||
required String name,
|
required String name,
|
||||||
required String email,
|
required String email,
|
||||||
String? passwordHash,
|
String? passwordHash,
|
||||||
DateTime? createdAt,
|
required DateTime createdAt,
|
||||||
DateTime? updatedAt,
|
required DateTime updatedAt,
|
||||||
}) = _User;
|
}) = _User;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,8 +20,8 @@ mixin _$User {
|
|||||||
String get name => throw _privateConstructorUsedError;
|
String get name => throw _privateConstructorUsedError;
|
||||||
String get email => throw _privateConstructorUsedError;
|
String get email => throw _privateConstructorUsedError;
|
||||||
String? get passwordHash => throw _privateConstructorUsedError;
|
String? get passwordHash => throw _privateConstructorUsedError;
|
||||||
DateTime? get createdAt => throw _privateConstructorUsedError;
|
DateTime get createdAt => throw _privateConstructorUsedError;
|
||||||
DateTime? get updatedAt => throw _privateConstructorUsedError;
|
DateTime get updatedAt => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
/// Create a copy of User
|
/// Create a copy of User
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@ -39,8 +39,8 @@ abstract class $UserCopyWith<$Res> {
|
|||||||
String name,
|
String name,
|
||||||
String email,
|
String email,
|
||||||
String? passwordHash,
|
String? passwordHash,
|
||||||
DateTime? createdAt,
|
DateTime createdAt,
|
||||||
DateTime? updatedAt});
|
DateTime updatedAt});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@ -62,8 +62,8 @@ class _$UserCopyWithImpl<$Res, $Val extends User>
|
|||||||
Object? name = null,
|
Object? name = null,
|
||||||
Object? email = null,
|
Object? email = null,
|
||||||
Object? passwordHash = freezed,
|
Object? passwordHash = freezed,
|
||||||
Object? createdAt = freezed,
|
Object? createdAt = null,
|
||||||
Object? updatedAt = freezed,
|
Object? updatedAt = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_value.copyWith(
|
return _then(_value.copyWith(
|
||||||
id: null == id
|
id: null == id
|
||||||
@ -82,14 +82,14 @@ class _$UserCopyWithImpl<$Res, $Val extends User>
|
|||||||
? _value.passwordHash
|
? _value.passwordHash
|
||||||
: passwordHash // ignore: cast_nullable_to_non_nullable
|
: passwordHash // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
createdAt: freezed == createdAt
|
createdAt: null == createdAt
|
||||||
? _value.createdAt
|
? _value.createdAt
|
||||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,
|
as DateTime,
|
||||||
updatedAt: freezed == updatedAt
|
updatedAt: null == updatedAt
|
||||||
? _value.updatedAt
|
? _value.updatedAt
|
||||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,
|
as DateTime,
|
||||||
) as $Val);
|
) as $Val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,8 +106,8 @@ abstract class _$$UserImplCopyWith<$Res> implements $UserCopyWith<$Res> {
|
|||||||
String name,
|
String name,
|
||||||
String email,
|
String email,
|
||||||
String? passwordHash,
|
String? passwordHash,
|
||||||
DateTime? createdAt,
|
DateTime createdAt,
|
||||||
DateTime? updatedAt});
|
DateTime updatedAt});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@ -126,8 +126,8 @@ class __$$UserImplCopyWithImpl<$Res>
|
|||||||
Object? name = null,
|
Object? name = null,
|
||||||
Object? email = null,
|
Object? email = null,
|
||||||
Object? passwordHash = freezed,
|
Object? passwordHash = freezed,
|
||||||
Object? createdAt = freezed,
|
Object? createdAt = null,
|
||||||
Object? updatedAt = freezed,
|
Object? updatedAt = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_$UserImpl(
|
return _then(_$UserImpl(
|
||||||
id: null == id
|
id: null == id
|
||||||
@ -146,14 +146,14 @@ class __$$UserImplCopyWithImpl<$Res>
|
|||||||
? _value.passwordHash
|
? _value.passwordHash
|
||||||
: passwordHash // ignore: cast_nullable_to_non_nullable
|
: passwordHash // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
createdAt: freezed == createdAt
|
createdAt: null == createdAt
|
||||||
? _value.createdAt
|
? _value.createdAt
|
||||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,
|
as DateTime,
|
||||||
updatedAt: freezed == updatedAt
|
updatedAt: null == updatedAt
|
||||||
? _value.updatedAt
|
? _value.updatedAt
|
||||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,
|
as DateTime,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,8 +166,8 @@ class _$UserImpl implements _User {
|
|||||||
required this.name,
|
required this.name,
|
||||||
required this.email,
|
required this.email,
|
||||||
this.passwordHash,
|
this.passwordHash,
|
||||||
this.createdAt,
|
required this.createdAt,
|
||||||
this.updatedAt});
|
required this.updatedAt});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final String id;
|
final String id;
|
||||||
@ -178,9 +178,9 @@ class _$UserImpl implements _User {
|
|||||||
@override
|
@override
|
||||||
final String? passwordHash;
|
final String? passwordHash;
|
||||||
@override
|
@override
|
||||||
final DateTime? createdAt;
|
final DateTime createdAt;
|
||||||
@override
|
@override
|
||||||
final DateTime? updatedAt;
|
final DateTime updatedAt;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
@ -222,8 +222,8 @@ abstract class _User implements User {
|
|||||||
required final String name,
|
required final String name,
|
||||||
required final String email,
|
required final String email,
|
||||||
final String? passwordHash,
|
final String? passwordHash,
|
||||||
final DateTime? createdAt,
|
required final DateTime createdAt,
|
||||||
final DateTime? updatedAt}) = _$UserImpl;
|
required final DateTime updatedAt}) = _$UserImpl;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get id;
|
String get id;
|
||||||
@ -234,9 +234,9 @@ abstract class _User implements User {
|
|||||||
@override
|
@override
|
||||||
String? get passwordHash;
|
String? get passwordHash;
|
||||||
@override
|
@override
|
||||||
DateTime? get createdAt;
|
DateTime get createdAt;
|
||||||
@override
|
@override
|
||||||
DateTime? get updatedAt;
|
DateTime get updatedAt;
|
||||||
|
|
||||||
/// Create a copy of User
|
/// Create a copy of User
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@ -9,6 +9,9 @@ abstract class ProjectRepository {
|
|||||||
/// Finds a project by its unique ID.
|
/// Finds a project by its unique ID.
|
||||||
TaskEither<IError, Project> findById(String id);
|
TaskEither<IError, Project> findById(String id);
|
||||||
|
|
||||||
|
// Finds all projects by a user's unique ID.
|
||||||
|
TaskEither<IError, List<Project>> findByUserId(String userId);
|
||||||
|
|
||||||
/// Updates an existing project.
|
/// Updates an existing project.
|
||||||
TaskEither<IError, Project> update(ProjectUpdate project);
|
TaskEither<IError, Project> update(ProjectUpdate project);
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ class UserDboMapper {
|
|||||||
name: target.name!,
|
name: target.name!,
|
||||||
email: target.email!,
|
email: target.email!,
|
||||||
passwordHash: target.password,
|
passwordHash: target.password,
|
||||||
createdAt: target.createdAt,
|
createdAt: target.createdAt!,
|
||||||
updatedAt: target.updatedAt,
|
updatedAt: target.updatedAt!,
|
||||||
));
|
));
|
||||||
|
|
||||||
TaskEither<IError, List<User>> listFrom(Iterable<UserDbo> targets) {
|
TaskEither<IError, List<User>> listFrom(Iterable<UserDbo> targets) {
|
||||||
|
@ -786,26 +786,26 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: test
|
name: test
|
||||||
sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f"
|
sha256: "8391fbe68d520daf2314121764d38e37f934c02fd7301ad18307bd93bd6b725d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.25.8"
|
version: "1.25.14"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
|
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.3"
|
version: "0.7.4"
|
||||||
test_core:
|
test_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_core
|
name: test_core
|
||||||
sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d"
|
sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.5"
|
version: "0.6.8"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -26,7 +26,7 @@ dependencies:
|
|||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
lints: ^3.0.0
|
lints: ^3.0.0
|
||||||
test: ^1.24.0
|
test: ^1.25.14
|
||||||
shelf_router_generator: ^1.1.0
|
shelf_router_generator: ^1.1.0
|
||||||
build_runner: ^2.4.14
|
build_runner: ^2.4.14
|
||||||
riverpod_generator: ^2.6.3
|
riverpod_generator: ^2.6.3
|
||||||
|
45
backend-dart/test/mocks/mock_database.dart
Normal file
45
backend-dart/test/mocks/mock_database.dart
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import 'package:backend_dart/domain/data/database.dart';
|
||||||
|
import 'package:backend_dart/domain/data/project_data_source.dart';
|
||||||
|
import 'package:backend_dart/domain/data/project_task_data_source.dart';
|
||||||
|
import 'package:backend_dart/domain/data/time_entry_data_source.dart';
|
||||||
|
import 'package:backend_dart/domain/data/user_data_source.dart';
|
||||||
|
import 'package:backend_dart/domain/entities/project.dart';
|
||||||
|
import 'package:backend_dart/domain/entities/project_task.dart';
|
||||||
|
import 'package:backend_dart/domain/entities/time_entry.dart';
|
||||||
|
import 'package:backend_dart/domain/entities/user.dart';
|
||||||
|
|
||||||
|
import 'mock_project_data_source.dart';
|
||||||
|
import 'mock_project_task_data_source.dart';
|
||||||
|
import 'mock_time_entry_data_source.dart';
|
||||||
|
import 'mock_user_data_source.dart';
|
||||||
|
|
||||||
|
class MockDatabase implements IDatabase {
|
||||||
|
final Map<String, User> _usersStore = {};
|
||||||
|
final Map<String, ProjectTask> _tasksStore = {};
|
||||||
|
final Map<String, Project> _projectsStore = {};
|
||||||
|
final Map<String, TimeEntry> _timeEntriesStore = {};
|
||||||
|
@override
|
||||||
|
Future<void> close() {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ProjectDataSource get projects => MockProjectDataSource(_projectsStore);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ProjectTaskDataSource get tasks => MockProjectTaskDataSource(_tasksStore);
|
||||||
|
|
||||||
|
@override
|
||||||
|
TimeEntryDataSource get timeEntries =>
|
||||||
|
MockTimeEntryDataSource(_timeEntriesStore);
|
||||||
|
|
||||||
|
@override
|
||||||
|
UserDataSource get users => MockUserDataSource(_usersStore);
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
_usersStore.clear();
|
||||||
|
_tasksStore.clear();
|
||||||
|
_projectsStore.clear();
|
||||||
|
_timeEntriesStore.clear();
|
||||||
|
}
|
||||||
|
}
|
137
backend-dart/test/mocks/mock_project_data_source.dart
Normal file
137
backend-dart/test/mocks/mock_project_data_source.dart
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import 'package:backend_dart/domain/data/project_data_source.dart';
|
||||||
|
import 'package:backend_dart/domain/entities/project.dart';
|
||||||
|
import 'package:backend_dart/domain/errors/app_error.dart';
|
||||||
|
import 'package:backend_dart/domain/errors/error.dart';
|
||||||
|
import 'package:fpdart/fpdart.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
class MockProjectDataSource implements ProjectDataSource {
|
||||||
|
MockProjectDataSource(this._store);
|
||||||
|
final Map<String, Project> _store;
|
||||||
|
final Uuid _uuid = Uuid();
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, Project> create(ProjectCreate project) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final id = _uuid.v4();
|
||||||
|
final newProject = Project(
|
||||||
|
id: id,
|
||||||
|
userId: project.userId,
|
||||||
|
name: project.name,
|
||||||
|
description: project.description,
|
||||||
|
clientId: project.clientId,
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
);
|
||||||
|
_store[id] = newProject;
|
||||||
|
return newProject;
|
||||||
|
},
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message: 'Failed to create project: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, Project> findById(String id) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final project = _store[id];
|
||||||
|
if (project == null) {
|
||||||
|
throw AppError.notFound('Project with ID $id not found');
|
||||||
|
}
|
||||||
|
return project;
|
||||||
|
},
|
||||||
|
(error, _) => error is AppError
|
||||||
|
? error
|
||||||
|
: AppError.databaseError(
|
||||||
|
message: 'Failed to find project by ID: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, List<Project>> findByUserId(String userId) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final projects =
|
||||||
|
_store.values.where((project) => project.userId == userId).toList();
|
||||||
|
return projects;
|
||||||
|
},
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message:
|
||||||
|
'Failed to fetch projects for user $userId: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, Project> update(ProjectUpdate project) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final existingProject = _store[project.id];
|
||||||
|
if (existingProject == null) {
|
||||||
|
throw AppError.notFound('Project with ID ${project.id} not found');
|
||||||
|
}
|
||||||
|
final updatedProject = existingProject.copyWith(
|
||||||
|
name: project.name ?? existingProject.name,
|
||||||
|
description: project.description ?? existingProject.description,
|
||||||
|
clientId: project.clientId ?? existingProject.clientId,
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
);
|
||||||
|
_store[project.id] = updatedProject;
|
||||||
|
return updatedProject;
|
||||||
|
},
|
||||||
|
(error, _) => error is AppError
|
||||||
|
? error
|
||||||
|
: AppError.databaseError(
|
||||||
|
message: 'Failed to update project: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, Project> delete(String id) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final project = _store.remove(id);
|
||||||
|
if (project == null) {
|
||||||
|
throw AppError.notFound('Project with ID $id not found');
|
||||||
|
}
|
||||||
|
return project;
|
||||||
|
},
|
||||||
|
(error, _) => error is AppError
|
||||||
|
? error
|
||||||
|
: AppError.databaseError(
|
||||||
|
message: 'Failed to delete project: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, List<Project>> findAll() {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async => _store.values.toList(),
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message: 'Failed to fetch all projects: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, String> generateId() {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
String id;
|
||||||
|
do {
|
||||||
|
id = _uuid.v4();
|
||||||
|
} while (_store.containsKey(id));
|
||||||
|
return id;
|
||||||
|
},
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message: 'Failed to generate ID: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
135
backend-dart/test/mocks/mock_project_task_data_source.dart
Normal file
135
backend-dart/test/mocks/mock_project_task_data_source.dart
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
import 'package:backend_dart/domain/data/project_task_data_source.dart';
|
||||||
|
import 'package:backend_dart/domain/entities/project_task.dart';
|
||||||
|
import 'package:backend_dart/domain/errors/app_error.dart';
|
||||||
|
import 'package:backend_dart/domain/errors/error.dart';
|
||||||
|
import 'package:fpdart/fpdart.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
class MockProjectTaskDataSource implements ProjectTaskDataSource {
|
||||||
|
MockProjectTaskDataSource(this._store);
|
||||||
|
final Map<String, ProjectTask> _store;
|
||||||
|
final Uuid _uuid = Uuid();
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, ProjectTask> create(ProjectTaskCreate task) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final id = _uuid.v4();
|
||||||
|
final newTask = ProjectTask(
|
||||||
|
id: id,
|
||||||
|
projectId: task.projectId,
|
||||||
|
name: task.name,
|
||||||
|
description: task.description,
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
);
|
||||||
|
_store[id] = newTask;
|
||||||
|
return newTask;
|
||||||
|
},
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message: 'Failed to create project task: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, ProjectTask> findById(String id) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final task = _store[id];
|
||||||
|
if (task == null) {
|
||||||
|
throw AppError.notFound('Project task with ID $id not found');
|
||||||
|
}
|
||||||
|
return task;
|
||||||
|
},
|
||||||
|
(error, _) => error is AppError
|
||||||
|
? error
|
||||||
|
: AppError.databaseError(
|
||||||
|
message: 'Failed to find project task by ID: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, List<ProjectTask>> findByProjectId(String projectId) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final tasks =
|
||||||
|
_store.values.where((task) => task.projectId == projectId).toList();
|
||||||
|
return tasks;
|
||||||
|
},
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message:
|
||||||
|
'Failed to fetch tasks for project $projectId: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, ProjectTask> update(ProjectTaskUpdate task) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final existingTask = _store[task.id];
|
||||||
|
if (existingTask == null) {
|
||||||
|
throw AppError.notFound('Project task with ID ${task.id} not found');
|
||||||
|
}
|
||||||
|
final updatedTask = existingTask.copyWith(
|
||||||
|
name: task.name ?? existingTask.name,
|
||||||
|
description: task.description ?? existingTask.description,
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
);
|
||||||
|
_store[task.id] = updatedTask;
|
||||||
|
return updatedTask;
|
||||||
|
},
|
||||||
|
(error, _) => error is AppError
|
||||||
|
? error
|
||||||
|
: AppError.databaseError(
|
||||||
|
message: 'Failed to update project task: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, ProjectTask> delete(String id) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final task = _store.remove(id);
|
||||||
|
if (task == null) {
|
||||||
|
throw AppError.notFound('Project task with ID $id not found');
|
||||||
|
}
|
||||||
|
return task;
|
||||||
|
},
|
||||||
|
(error, _) => error is AppError
|
||||||
|
? error
|
||||||
|
: AppError.databaseError(
|
||||||
|
message: 'Failed to delete project task: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, List<ProjectTask>> findAll() {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async => _store.values.toList(),
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message: 'Failed to fetch all project tasks: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, String> generateId() {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
String id;
|
||||||
|
do {
|
||||||
|
id = _uuid.v4();
|
||||||
|
} while (_store.containsKey(id));
|
||||||
|
return id;
|
||||||
|
},
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message: 'Failed to generate ID: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
156
backend-dart/test/mocks/mock_time_entry_data_source.dart
Normal file
156
backend-dart/test/mocks/mock_time_entry_data_source.dart
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
import 'package:backend_dart/domain/data/time_entry_data_source.dart';
|
||||||
|
import 'package:backend_dart/domain/entities/time_entry.dart';
|
||||||
|
import 'package:backend_dart/domain/errors/app_error.dart';
|
||||||
|
import 'package:backend_dart/domain/errors/error.dart';
|
||||||
|
import 'package:fpdart/fpdart.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
class MockTimeEntryDataSource implements TimeEntryDataSource {
|
||||||
|
MockTimeEntryDataSource(this._store);
|
||||||
|
final Map<String, TimeEntry> _store;
|
||||||
|
final Uuid _uuid = Uuid();
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, TimeEntry> create(TimeEntryCreate timeEntry) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final id = _uuid.v4();
|
||||||
|
final newEntry = TimeEntry(
|
||||||
|
id: id,
|
||||||
|
userId: timeEntry.userId,
|
||||||
|
projectId: timeEntry.projectId,
|
||||||
|
startTime: timeEntry.startTime,
|
||||||
|
endTime: timeEntry.endTime,
|
||||||
|
description: timeEntry.description,
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
);
|
||||||
|
_store[id] = newEntry;
|
||||||
|
return newEntry;
|
||||||
|
},
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message: 'Failed to create time entry: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, TimeEntry> findById(String id) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final entry = _store[id];
|
||||||
|
if (entry == null) {
|
||||||
|
throw AppError.notFound('Time entry with ID $id not found');
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
},
|
||||||
|
(error, _) => error is AppError
|
||||||
|
? error
|
||||||
|
: AppError.databaseError(
|
||||||
|
message: 'Failed to find time entry by ID: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, List<TimeEntry>> findByUserId(String userId) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final entries =
|
||||||
|
_store.values.where((entry) => entry.userId == userId).toList();
|
||||||
|
return entries;
|
||||||
|
},
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message:
|
||||||
|
'Failed to fetch time entries for user $userId: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, List<TimeEntry>> findByProjectId(String projectId) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final entries = _store.values
|
||||||
|
.where((entry) => entry.projectId == projectId)
|
||||||
|
.toList();
|
||||||
|
return entries;
|
||||||
|
},
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message:
|
||||||
|
'Failed to fetch time entries for project $projectId: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, TimeEntry> update(TimeEntryUpdate timeEntry) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final existingEntry = _store[timeEntry.id];
|
||||||
|
if (existingEntry == null) {
|
||||||
|
throw AppError.notFound(
|
||||||
|
'Time entry with ID ${timeEntry.id} not found');
|
||||||
|
}
|
||||||
|
final updatedEntry = existingEntry.copyWith(
|
||||||
|
startTime: timeEntry.startTime ?? existingEntry.startTime,
|
||||||
|
endTime: timeEntry.endTime ?? existingEntry.endTime,
|
||||||
|
description: timeEntry.description ?? existingEntry.description,
|
||||||
|
projectId: timeEntry.projectId ?? existingEntry.projectId,
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
);
|
||||||
|
_store[timeEntry.id] = updatedEntry;
|
||||||
|
return updatedEntry;
|
||||||
|
},
|
||||||
|
(error, _) => error is AppError
|
||||||
|
? error
|
||||||
|
: AppError.databaseError(
|
||||||
|
message: 'Failed to update time entry: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, TimeEntry> delete(String id) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final entry = _store.remove(id);
|
||||||
|
if (entry == null) {
|
||||||
|
throw AppError.notFound('Time entry with ID $id not found');
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
},
|
||||||
|
(error, _) => error is AppError
|
||||||
|
? error
|
||||||
|
: AppError.databaseError(
|
||||||
|
message: 'Failed to delete time entry: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, List<TimeEntry>> findAll() {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async => _store.values.toList(),
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message: 'Failed to fetch all time entries: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, String> generateId() {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
String id;
|
||||||
|
do {
|
||||||
|
id = _uuid.v4();
|
||||||
|
} while (_store.containsKey(id));
|
||||||
|
return id;
|
||||||
|
},
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message: 'Failed to generate ID: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
144
backend-dart/test/mocks/mock_user_data_source.dart
Normal file
144
backend-dart/test/mocks/mock_user_data_source.dart
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
import 'package:backend_dart/common/extensions.dart';
|
||||||
|
import 'package:backend_dart/common/secure_hash.dart';
|
||||||
|
import 'package:backend_dart/domain/data/user_data_source.dart';
|
||||||
|
import 'package:backend_dart/domain/entities/user.dart';
|
||||||
|
import 'package:backend_dart/domain/errors/app_error.dart';
|
||||||
|
import 'package:backend_dart/domain/errors/error.dart';
|
||||||
|
import 'package:fpdart/fpdart.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
class MockUserDataSource implements UserDataSource {
|
||||||
|
MockUserDataSource(this.store);
|
||||||
|
final Map<String, User> store;
|
||||||
|
final Uuid _uuid = Uuid();
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, User> create(UserCreate user) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final id = _uuid.v4();
|
||||||
|
final newUser = User(
|
||||||
|
id: id,
|
||||||
|
email: user.email,
|
||||||
|
passwordHash: generateSecureHash(user.password),
|
||||||
|
name: user.name,
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
updatedAt: DateTime.now());
|
||||||
|
store[id] = newUser;
|
||||||
|
return newUser;
|
||||||
|
},
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message: 'Failed to create user: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, User> findByEmail(String email) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final user = store.values
|
||||||
|
.where(
|
||||||
|
(user) => user.email == email,
|
||||||
|
)
|
||||||
|
.firstOrNull;
|
||||||
|
if (user == null) {
|
||||||
|
throw AppError.notFound('User with email $email not found');
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
},
|
||||||
|
(error, _) => error is AppError
|
||||||
|
? error
|
||||||
|
: AppError.databaseError(
|
||||||
|
message: 'Failed to find user by email: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, User> findById(String id) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final user = store[id];
|
||||||
|
if (user == null) {
|
||||||
|
throw AppError.notFound('User with ID $id not found');
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
},
|
||||||
|
(error, _) => error is AppError
|
||||||
|
? error
|
||||||
|
: AppError.databaseError(
|
||||||
|
message: 'Failed to find user by ID: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, User> update(UserUpdate user) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final existingUser = store[user.id];
|
||||||
|
if (existingUser == null) {
|
||||||
|
throw AppError.notFound('User with ID ${user.id} not found');
|
||||||
|
}
|
||||||
|
final updatedUser = existingUser.copyWith(
|
||||||
|
email: user.email ?? existingUser.email,
|
||||||
|
passwordHash: user.password.let(generateSecureHash) ??
|
||||||
|
existingUser.passwordHash,
|
||||||
|
name: user.name ?? existingUser.name,
|
||||||
|
);
|
||||||
|
store[user.id] = updatedUser;
|
||||||
|
return updatedUser;
|
||||||
|
},
|
||||||
|
(error, _) => error is AppError
|
||||||
|
? error
|
||||||
|
: AppError.databaseError(
|
||||||
|
message: 'Failed to update user: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, User> delete(String id) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
final user = store.remove(id);
|
||||||
|
if (user == null) {
|
||||||
|
throw AppError.notFound('User with ID $id not found');
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
},
|
||||||
|
(error, _) => error is AppError
|
||||||
|
? error
|
||||||
|
: AppError.databaseError(
|
||||||
|
message: 'Failed to delete user: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, List<User>> findAll() {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async => store.values.toList(),
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message: 'Failed to fetch all users: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TaskEither<IError, String> generateId() {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
String id;
|
||||||
|
do {
|
||||||
|
id = _uuid.v4();
|
||||||
|
} while (store.containsKey(id));
|
||||||
|
return id;
|
||||||
|
},
|
||||||
|
(error, _) => AppError.databaseError(
|
||||||
|
message: 'Failed to generate ID: ${error.toString()}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
199
backend-dart/test/project_repository_tests.dart
Normal file
199
backend-dart/test/project_repository_tests.dart
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
import 'package:backend_dart/application/repository/project_repository_impl.dart';
|
||||||
|
import 'package:backend_dart/domain/entities/project.dart';
|
||||||
|
import 'package:backend_dart/domain/repository/project_repository.dart';
|
||||||
|
import 'package:fpdart/fpdart.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
import 'mocks/mock_database.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late MockDatabase database;
|
||||||
|
late ProjectRepository projectRepository;
|
||||||
|
|
||||||
|
setUpAll(() {
|
||||||
|
database = MockDatabase();
|
||||||
|
projectRepository = ProjectRepositoryImpl(database);
|
||||||
|
});
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
database.clear(); // Clear the database before each test
|
||||||
|
});
|
||||||
|
|
||||||
|
test('create project', () async {
|
||||||
|
final projectCreate = ProjectCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
name: 'Test Project',
|
||||||
|
description: 'This is a test project',
|
||||||
|
clientId: 'client123',
|
||||||
|
);
|
||||||
|
|
||||||
|
final project = await projectRepository.create(projectCreate).run();
|
||||||
|
expect(project.isRight(), true, reason: 'Result should be right');
|
||||||
|
|
||||||
|
project.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(project) {
|
||||||
|
expect(project.userId, projectCreate.userId,
|
||||||
|
reason: 'User ID should be ${projectCreate.userId}');
|
||||||
|
expect(project.name, projectCreate.name,
|
||||||
|
reason: 'Name should be ${projectCreate.name}');
|
||||||
|
expect(project.description, projectCreate.description,
|
||||||
|
reason: 'Description should be ${projectCreate.description}');
|
||||||
|
expect(project.clientId, projectCreate.clientId,
|
||||||
|
reason: 'Client ID should be ${projectCreate.clientId}');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find project by id', () async {
|
||||||
|
final projectCreate = ProjectCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
name: 'Test Project',
|
||||||
|
description: 'This is a test project',
|
||||||
|
clientId: 'client123',
|
||||||
|
);
|
||||||
|
|
||||||
|
final createdProject = await projectRepository.create(projectCreate).run();
|
||||||
|
|
||||||
|
createdProject.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(project) async {
|
||||||
|
final foundProject = await projectRepository.findById(project.id).run();
|
||||||
|
|
||||||
|
foundProject.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(project) {
|
||||||
|
expect(project.name, projectCreate.name,
|
||||||
|
reason: 'Name should be ${projectCreate.name}');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find projects by user id', () async {
|
||||||
|
final project1 = ProjectCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
name: 'Project 1',
|
||||||
|
description: 'Description 1',
|
||||||
|
clientId: 'client123',
|
||||||
|
);
|
||||||
|
final project2 = ProjectCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
name: 'Project 2',
|
||||||
|
description: 'Description 2',
|
||||||
|
clientId: 'client123',
|
||||||
|
);
|
||||||
|
|
||||||
|
await projectRepository.create(project1).run();
|
||||||
|
await projectRepository.create(project2).run();
|
||||||
|
|
||||||
|
final projects = await projectRepository.findByUserId('user123').run();
|
||||||
|
|
||||||
|
projects.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(projects) {
|
||||||
|
expect(projects.length, 2, reason: 'Should return two projects');
|
||||||
|
expect(
|
||||||
|
projects.map((p) => p.name).toList(),
|
||||||
|
containsAll([project1.name, project2.name]),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('update project', () async {
|
||||||
|
final projectCreate = ProjectCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
name: 'Old Name',
|
||||||
|
description: 'Old Description',
|
||||||
|
clientId: 'client123',
|
||||||
|
);
|
||||||
|
|
||||||
|
final createdProject = await projectRepository.create(projectCreate).run();
|
||||||
|
|
||||||
|
createdProject.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(project) async {
|
||||||
|
final projectUpdate = ProjectUpdate(
|
||||||
|
id: project.id,
|
||||||
|
name: 'Updated Name',
|
||||||
|
description: 'Updated Description',
|
||||||
|
);
|
||||||
|
|
||||||
|
final updatedProject =
|
||||||
|
await projectRepository.update(projectUpdate).run();
|
||||||
|
|
||||||
|
updatedProject.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(project) {
|
||||||
|
expect(project.name, 'Updated Name',
|
||||||
|
reason: 'Name should be Updated Name');
|
||||||
|
expect(project.description, 'Updated Description',
|
||||||
|
reason: 'Description should be Updated Description');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('delete project', () async {
|
||||||
|
final projectCreate = ProjectCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
name: 'Test Project',
|
||||||
|
description: 'This is a test project',
|
||||||
|
clientId: 'client123',
|
||||||
|
);
|
||||||
|
|
||||||
|
final createdProject = await projectRepository.create(projectCreate).run();
|
||||||
|
|
||||||
|
createdProject.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(project) async {
|
||||||
|
final deletedProject = await projectRepository.delete(project.id).run();
|
||||||
|
|
||||||
|
deletedProject.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(project) {
|
||||||
|
expect(project.id, createdProject.match((e) => null, identity)?.id,
|
||||||
|
reason: 'Deleted project ID should match created project ID');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await projectRepository.findById(project.id).run();
|
||||||
|
expect(result.isLeft(), true, reason: 'Project should no longer exist');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find all projects', () async {
|
||||||
|
final project1 = ProjectCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
name: 'Project 1',
|
||||||
|
description: 'Description 1',
|
||||||
|
clientId: 'client123',
|
||||||
|
);
|
||||||
|
final project2 = ProjectCreate(
|
||||||
|
userId: 'user456',
|
||||||
|
name: 'Project 2',
|
||||||
|
description: 'Description 2',
|
||||||
|
clientId: 'client123',
|
||||||
|
);
|
||||||
|
|
||||||
|
await projectRepository.create(project1).run();
|
||||||
|
await projectRepository.create(project2).run();
|
||||||
|
|
||||||
|
final projects = await projectRepository.findAll().run();
|
||||||
|
|
||||||
|
projects.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(projects) {
|
||||||
|
expect(projects.length, 2, reason: 'Should return all projects');
|
||||||
|
expect(
|
||||||
|
projects.map((p) => p.name).toList(),
|
||||||
|
containsAll([project1.name, project2.name]),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
191
backend-dart/test/project_task_repository_tests.dart
Normal file
191
backend-dart/test/project_task_repository_tests.dart
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
import 'package:backend_dart/application/repository/project_task_repository_impl.dart';
|
||||||
|
import 'package:backend_dart/domain/entities/project_task.dart';
|
||||||
|
import 'package:backend_dart/domain/repository/project_task_repository.dart';
|
||||||
|
import 'package:fpdart/fpdart.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
import 'mocks/mock_database.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late MockDatabase database;
|
||||||
|
late ProjectTaskRepository projectTaskRepository;
|
||||||
|
|
||||||
|
setUpAll(() {
|
||||||
|
database = MockDatabase();
|
||||||
|
projectTaskRepository = ProjectTaskRepositoryImpl(database);
|
||||||
|
});
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
database.clear(); // Clear the database before each test
|
||||||
|
});
|
||||||
|
|
||||||
|
test('create project task', () async {
|
||||||
|
final projectTaskCreate = ProjectTaskCreate(
|
||||||
|
projectId: 'project123',
|
||||||
|
name: 'Test Task',
|
||||||
|
description: 'This is a test task',
|
||||||
|
);
|
||||||
|
|
||||||
|
final projectTask =
|
||||||
|
await projectTaskRepository.create(projectTaskCreate).run();
|
||||||
|
expect(projectTask.isRight(), true, reason: 'Result should be right');
|
||||||
|
|
||||||
|
projectTask.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(task) {
|
||||||
|
expect(task.projectId, projectTaskCreate.projectId,
|
||||||
|
reason: 'Project ID should match');
|
||||||
|
expect(task.name, projectTaskCreate.name,
|
||||||
|
reason: 'Task name should match');
|
||||||
|
expect(task.description, projectTaskCreate.description,
|
||||||
|
reason: 'Description should match');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find project task by id', () async {
|
||||||
|
final projectTaskCreate = ProjectTaskCreate(
|
||||||
|
projectId: 'project123',
|
||||||
|
name: 'Test Task',
|
||||||
|
description: 'This is a test task',
|
||||||
|
);
|
||||||
|
|
||||||
|
final createdTask =
|
||||||
|
await projectTaskRepository.create(projectTaskCreate).run();
|
||||||
|
|
||||||
|
createdTask.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(task) async {
|
||||||
|
final foundTask = await projectTaskRepository.findById(task.id).run();
|
||||||
|
|
||||||
|
foundTask.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(task) {
|
||||||
|
expect(task.id, createdTask.match((e) => null, identity)?.id,
|
||||||
|
reason: 'Task ID should match');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find tasks by project id', () async {
|
||||||
|
final task1 = ProjectTaskCreate(
|
||||||
|
projectId: 'project123',
|
||||||
|
name: 'Task 1',
|
||||||
|
description: 'First task',
|
||||||
|
);
|
||||||
|
final task2 = ProjectTaskCreate(
|
||||||
|
projectId: 'project123',
|
||||||
|
name: 'Task 2',
|
||||||
|
description: 'Second task',
|
||||||
|
);
|
||||||
|
|
||||||
|
await projectTaskRepository.create(task1).run();
|
||||||
|
await projectTaskRepository.create(task2).run();
|
||||||
|
|
||||||
|
final tasks =
|
||||||
|
await projectTaskRepository.findByProjectId('project123').run();
|
||||||
|
|
||||||
|
tasks.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(tasks) {
|
||||||
|
expect(tasks.length, 2, reason: 'Should return two tasks');
|
||||||
|
expect(
|
||||||
|
tasks.map((t) => t.name).toList(),
|
||||||
|
containsAll([task1.name, task2.name]),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('update project task', () async {
|
||||||
|
final projectTaskCreate = ProjectTaskCreate(
|
||||||
|
projectId: 'project123',
|
||||||
|
name: 'Initial Task',
|
||||||
|
description: 'Initial Description',
|
||||||
|
);
|
||||||
|
|
||||||
|
final createdTask =
|
||||||
|
await projectTaskRepository.create(projectTaskCreate).run();
|
||||||
|
|
||||||
|
createdTask.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(task) async {
|
||||||
|
final taskUpdate = ProjectTaskUpdate(
|
||||||
|
id: task.id,
|
||||||
|
name: 'Updated Task',
|
||||||
|
);
|
||||||
|
|
||||||
|
final updatedTask =
|
||||||
|
await projectTaskRepository.update(taskUpdate).run();
|
||||||
|
|
||||||
|
updatedTask.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(task) {
|
||||||
|
expect(task.name, 'Updated Task',
|
||||||
|
reason: 'Task name should be updated');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('delete project task', () async {
|
||||||
|
final projectTaskCreate = ProjectTaskCreate(
|
||||||
|
projectId: 'project123',
|
||||||
|
name: 'Task to delete',
|
||||||
|
description: 'Task description',
|
||||||
|
);
|
||||||
|
|
||||||
|
final createdTask =
|
||||||
|
await projectTaskRepository.create(projectTaskCreate).run();
|
||||||
|
|
||||||
|
createdTask.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(task) async {
|
||||||
|
final deletedTask = await projectTaskRepository.delete(task.id).run();
|
||||||
|
|
||||||
|
deletedTask.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(task) {
|
||||||
|
expect(task.id, createdTask.match((e) => null, identity)?.id,
|
||||||
|
reason: 'Deleted task ID should match created task ID');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await projectTaskRepository.findById(task.id).run();
|
||||||
|
expect(result.isLeft(), true, reason: 'Task should no longer exist');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find all project tasks', () async {
|
||||||
|
final task1 = ProjectTaskCreate(
|
||||||
|
projectId: 'project123',
|
||||||
|
name: 'Task 1',
|
||||||
|
description: 'Description 1',
|
||||||
|
);
|
||||||
|
final task2 = ProjectTaskCreate(
|
||||||
|
projectId: 'project456',
|
||||||
|
name: 'Task 2',
|
||||||
|
description: 'Description 2',
|
||||||
|
);
|
||||||
|
|
||||||
|
await projectTaskRepository.create(task1).run();
|
||||||
|
await projectTaskRepository.create(task2).run();
|
||||||
|
|
||||||
|
final tasks = await projectTaskRepository.findAll().run();
|
||||||
|
|
||||||
|
tasks.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(tasks) {
|
||||||
|
expect(tasks.length, 2, reason: 'Should return all tasks');
|
||||||
|
expect(
|
||||||
|
tasks.map((t) => t.name),
|
||||||
|
containsAll([task1.name, task2.name]),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
239
backend-dart/test/time_entries_repository_tests.dart
Normal file
239
backend-dart/test/time_entries_repository_tests.dart
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
import 'package:backend_dart/application/repository/time_entry_repository_impl.dart';
|
||||||
|
import 'package:backend_dart/domain/entities/time_entry.dart';
|
||||||
|
import 'package:backend_dart/domain/repository/time_entry_repository.dart';
|
||||||
|
import 'package:fpdart/fpdart.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
import 'mocks/mock_database.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late MockDatabase database;
|
||||||
|
late TimeEntryRepository timeEntryRepository;
|
||||||
|
|
||||||
|
setUpAll(() {
|
||||||
|
database = MockDatabase();
|
||||||
|
timeEntryRepository = TimeEntryRepositoryImpl(database);
|
||||||
|
});
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
database.clear(); // Clear the database before each test
|
||||||
|
});
|
||||||
|
|
||||||
|
test('create time entry', () async {
|
||||||
|
final timeEntryCreate = TimeEntryCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
projectId: 'project123',
|
||||||
|
startTime: DateTime.now(),
|
||||||
|
endTime: DateTime.now().add(Duration(hours: 1)),
|
||||||
|
description: 'Working on project',
|
||||||
|
);
|
||||||
|
|
||||||
|
final timeEntry = await timeEntryRepository.create(timeEntryCreate).run();
|
||||||
|
expect(timeEntry.isRight(), true, reason: 'Result should be right');
|
||||||
|
|
||||||
|
timeEntry.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(timeEntry) {
|
||||||
|
expect(timeEntry.userId, timeEntryCreate.userId,
|
||||||
|
reason: 'User ID should match');
|
||||||
|
expect(timeEntry.projectId, timeEntryCreate.projectId,
|
||||||
|
reason: 'Project ID should match');
|
||||||
|
expect(timeEntry.startTime, timeEntryCreate.startTime,
|
||||||
|
reason: 'Start time should match');
|
||||||
|
expect(timeEntry.endTime, timeEntryCreate.endTime,
|
||||||
|
reason: 'End time should match');
|
||||||
|
expect(timeEntry.description, timeEntryCreate.description,
|
||||||
|
reason: 'Description should match');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find time entry by id', () async {
|
||||||
|
final timeEntryCreate = TimeEntryCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
projectId: 'project123',
|
||||||
|
startTime: DateTime.now(),
|
||||||
|
endTime: DateTime.now().add(Duration(hours: 1)),
|
||||||
|
description: 'Working on project',
|
||||||
|
);
|
||||||
|
|
||||||
|
final createdEntry =
|
||||||
|
await timeEntryRepository.create(timeEntryCreate).run();
|
||||||
|
|
||||||
|
createdEntry.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(entry) async {
|
||||||
|
final foundEntry = await timeEntryRepository.findById(entry.id).run();
|
||||||
|
|
||||||
|
foundEntry.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(entry) {
|
||||||
|
expect(entry.id, createdEntry.match((e) => null, identity)?.id,
|
||||||
|
reason: 'ID should match the created entry');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find time entries by user id', () async {
|
||||||
|
final timeEntry1 = TimeEntryCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
projectId: 'project123',
|
||||||
|
startTime: DateTime.now(),
|
||||||
|
endTime: DateTime.now().add(Duration(hours: 1)),
|
||||||
|
description: 'Task 1',
|
||||||
|
);
|
||||||
|
final timeEntry2 = TimeEntryCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
projectId: 'project456',
|
||||||
|
startTime: DateTime.now().add(Duration(hours: 2)),
|
||||||
|
endTime: DateTime.now().add(Duration(hours: 3)),
|
||||||
|
description: 'Task 2',
|
||||||
|
);
|
||||||
|
|
||||||
|
await timeEntryRepository.create(timeEntry1).run();
|
||||||
|
await timeEntryRepository.create(timeEntry2).run();
|
||||||
|
|
||||||
|
final entries = await timeEntryRepository.findByUserId('user123').run();
|
||||||
|
|
||||||
|
entries.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(entries) {
|
||||||
|
expect(entries.length, 2, reason: 'Should return two entries');
|
||||||
|
expect(entries.map((e) => e.description),
|
||||||
|
containsAll([timeEntry1.description, timeEntry2.description]));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find time entries by project id', () async {
|
||||||
|
final timeEntry1 = TimeEntryCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
projectId: 'project123',
|
||||||
|
startTime: DateTime.now(),
|
||||||
|
endTime: DateTime.now().add(Duration(hours: 1)),
|
||||||
|
description: 'Task 1',
|
||||||
|
);
|
||||||
|
final timeEntry2 = TimeEntryCreate(
|
||||||
|
userId: 'user456',
|
||||||
|
projectId: 'project123',
|
||||||
|
startTime: DateTime.now().add(Duration(hours: 2)),
|
||||||
|
endTime: DateTime.now().add(Duration(hours: 3)),
|
||||||
|
description: 'Task 2',
|
||||||
|
);
|
||||||
|
|
||||||
|
await timeEntryRepository.create(timeEntry1).run();
|
||||||
|
await timeEntryRepository.create(timeEntry2).run();
|
||||||
|
|
||||||
|
final entries =
|
||||||
|
await timeEntryRepository.findByProjectId('project123').run();
|
||||||
|
|
||||||
|
entries.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(entries) {
|
||||||
|
expect(entries.length, 2, reason: 'Should return two entries');
|
||||||
|
expect(entries.map((e) => e.description),
|
||||||
|
containsAll([timeEntry1.description, timeEntry2.description]));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('update time entry', () async {
|
||||||
|
final timeEntryCreate = TimeEntryCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
projectId: 'project123',
|
||||||
|
startTime: DateTime.now(),
|
||||||
|
endTime: DateTime.now().add(Duration(hours: 1)),
|
||||||
|
description: 'Initial Task',
|
||||||
|
);
|
||||||
|
|
||||||
|
final createdEntry =
|
||||||
|
await timeEntryRepository.create(timeEntryCreate).run();
|
||||||
|
|
||||||
|
createdEntry.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(entry) async {
|
||||||
|
final timeEntryUpdate = TimeEntryUpdate(
|
||||||
|
id: entry.id,
|
||||||
|
description: 'Updated Task',
|
||||||
|
);
|
||||||
|
|
||||||
|
final updatedEntry =
|
||||||
|
await timeEntryRepository.update(timeEntryUpdate).run();
|
||||||
|
|
||||||
|
updatedEntry.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(entry) {
|
||||||
|
expect(entry.description, 'Updated Task',
|
||||||
|
reason: 'Description should be updated');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('delete time entry', () async {
|
||||||
|
final timeEntryCreate = TimeEntryCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
projectId: 'project123',
|
||||||
|
startTime: DateTime.now(),
|
||||||
|
endTime: DateTime.now().add(Duration(hours: 1)),
|
||||||
|
description: 'Task to delete',
|
||||||
|
);
|
||||||
|
|
||||||
|
final createdEntry =
|
||||||
|
await timeEntryRepository.create(timeEntryCreate).run();
|
||||||
|
|
||||||
|
createdEntry.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(entry) async {
|
||||||
|
final deletedEntry = await timeEntryRepository.delete(entry.id).run();
|
||||||
|
|
||||||
|
deletedEntry.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(entry) {
|
||||||
|
expect(entry.id, createdEntry.match((e) => null, identity)?.id,
|
||||||
|
reason: 'Deleted entry ID should match created entry ID');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await timeEntryRepository.findById(entry.id).run();
|
||||||
|
expect(result.isLeft(), true, reason: 'Entry should no longer exist');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find all time entries', () async {
|
||||||
|
final timeEntry1 = TimeEntryCreate(
|
||||||
|
userId: 'user123',
|
||||||
|
projectId: 'project123',
|
||||||
|
startTime: DateTime.now(),
|
||||||
|
endTime: DateTime.now().add(Duration(hours: 1)),
|
||||||
|
description: 'Task 1',
|
||||||
|
);
|
||||||
|
final timeEntry2 = TimeEntryCreate(
|
||||||
|
userId: 'user456',
|
||||||
|
projectId: 'project456',
|
||||||
|
startTime: DateTime.now().add(Duration(hours: 2)),
|
||||||
|
endTime: DateTime.now().add(Duration(hours: 3)),
|
||||||
|
description: 'Task 2',
|
||||||
|
);
|
||||||
|
|
||||||
|
await timeEntryRepository.create(timeEntry1).run();
|
||||||
|
await timeEntryRepository.create(timeEntry2).run();
|
||||||
|
|
||||||
|
final entries = await timeEntryRepository.findAll().run();
|
||||||
|
|
||||||
|
entries.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(entries) {
|
||||||
|
expect(entries.length, 2, reason: 'Should return all entries');
|
||||||
|
expect(
|
||||||
|
entries.map((e) => e.description),
|
||||||
|
containsAll([timeEntry1.description, timeEntry2.description]),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
202
backend-dart/test/user_repository_tests.dart
Normal file
202
backend-dart/test/user_repository_tests.dart
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
import 'package:backend_dart/application/repository/user_repository_impl.dart';
|
||||||
|
import 'package:backend_dart/common/secure_hash.dart';
|
||||||
|
import 'package:backend_dart/domain/entities/user.dart';
|
||||||
|
import 'package:backend_dart/domain/repository/user_repository.dart';
|
||||||
|
import 'package:fpdart/fpdart.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
import 'mocks/mock_database.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late MockDatabase database;
|
||||||
|
late UserRepository userRepository;
|
||||||
|
|
||||||
|
setUpAll(() {
|
||||||
|
database = MockDatabase();
|
||||||
|
userRepository = UserRepositoryImpl(database);
|
||||||
|
});
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
database.clear(); // Für jeden Test die Datenbank zurücksetzen
|
||||||
|
});
|
||||||
|
|
||||||
|
test('generateSecureHash', () {
|
||||||
|
final password = 'password';
|
||||||
|
final hash = generateSecureHash(password);
|
||||||
|
final expected =
|
||||||
|
'5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8';
|
||||||
|
expect(hash, expected, reason: 'Hash should be $expected');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('create user', () async {
|
||||||
|
database.clear();
|
||||||
|
|
||||||
|
final userCreate = UserCreate(
|
||||||
|
email: 'user@example.com',
|
||||||
|
password: 'password',
|
||||||
|
name: 'John Doe1',
|
||||||
|
);
|
||||||
|
final user = await userRepository.create(userCreate).run();
|
||||||
|
expect(user.isRight(), true, reason: 'Result should be right');
|
||||||
|
|
||||||
|
user.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(user) {
|
||||||
|
final hashedPassword = generateSecureHash(userCreate.password);
|
||||||
|
expect(user.email, userCreate.email,
|
||||||
|
reason: 'Email should be ${userCreate.email}');
|
||||||
|
expect(user.name, userCreate.name,
|
||||||
|
reason: 'Name should be ${userCreate.name}');
|
||||||
|
expect(user.passwordHash, hashedPassword,
|
||||||
|
reason: 'Password hash should be $hashedPassword');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find user by email', () async {
|
||||||
|
database.clear();
|
||||||
|
|
||||||
|
final userCreate = UserCreate(
|
||||||
|
email: 'user@example.com',
|
||||||
|
password: 'password',
|
||||||
|
name: 'John Doe2',
|
||||||
|
);
|
||||||
|
await userRepository.create(userCreate).run();
|
||||||
|
|
||||||
|
final foundUser = await userRepository.findByEmail(userCreate.email).run();
|
||||||
|
|
||||||
|
foundUser.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(user) {
|
||||||
|
final hashedPassword = generateSecureHash(userCreate.password);
|
||||||
|
expect(user.email, userCreate.email,
|
||||||
|
reason: 'Email should be ${userCreate.email}');
|
||||||
|
expect(user.name, userCreate.name,
|
||||||
|
reason: 'Name should be ${userCreate.name}');
|
||||||
|
expect(user.passwordHash, hashedPassword,
|
||||||
|
reason: 'Password hash should be $hashedPassword');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find user by id', () async {
|
||||||
|
database.clear();
|
||||||
|
|
||||||
|
final userCreate = UserCreate(
|
||||||
|
email: 'user@example.com',
|
||||||
|
password: 'password',
|
||||||
|
name: 'John Doe3',
|
||||||
|
);
|
||||||
|
final createdUser = await userRepository.create(userCreate).run();
|
||||||
|
|
||||||
|
createdUser.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(user) async {
|
||||||
|
final foundUser = await userRepository.findById(user.id).run();
|
||||||
|
|
||||||
|
foundUser.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(user) {
|
||||||
|
final hashedPassword = generateSecureHash(userCreate.password);
|
||||||
|
expect(user.email, userCreate.email,
|
||||||
|
reason: 'Email should be ${userCreate.email}');
|
||||||
|
expect(user.name, userCreate.name,
|
||||||
|
reason: 'Name should be ${userCreate.name}');
|
||||||
|
expect(user.passwordHash, hashedPassword,
|
||||||
|
reason: 'Password hash should be $hashedPassword');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('update user', () async {
|
||||||
|
database.clear();
|
||||||
|
|
||||||
|
final userCreate = UserCreate(
|
||||||
|
email: 'user@example.com',
|
||||||
|
password: 'password',
|
||||||
|
name: 'John Doe4',
|
||||||
|
);
|
||||||
|
final createdUser = await userRepository.create(userCreate).run();
|
||||||
|
|
||||||
|
createdUser.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(user) async {
|
||||||
|
final userUpdate = UserUpdate(
|
||||||
|
id: user.id,
|
||||||
|
name: 'Jane Doe',
|
||||||
|
);
|
||||||
|
|
||||||
|
final updatedUser = await userRepository.update(userUpdate).run();
|
||||||
|
|
||||||
|
updatedUser.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(user) {
|
||||||
|
expect(user.name, 'Jane Doe',
|
||||||
|
reason: 'Updated name should be Jane Doe');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('delete user', () async {
|
||||||
|
database.clear();
|
||||||
|
|
||||||
|
final userCreate = UserCreate(
|
||||||
|
email: 'user@example.com',
|
||||||
|
password: 'password',
|
||||||
|
name: 'John Doe5',
|
||||||
|
);
|
||||||
|
final createdUser = await userRepository.create(userCreate).run();
|
||||||
|
|
||||||
|
createdUser.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(user) async {
|
||||||
|
final deletedUser = await userRepository.delete(user.id).run();
|
||||||
|
|
||||||
|
deletedUser.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(user) {
|
||||||
|
expect(user.id, createdUser.match((e) => null, identity)?.id,
|
||||||
|
reason: 'Deleted user ID should match created user ID');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await userRepository.findById(user.id).run();
|
||||||
|
expect(result.isLeft(), true, reason: 'User should no longer exist');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('find all users', () async {
|
||||||
|
database.clear();
|
||||||
|
|
||||||
|
final user1 = UserCreate(
|
||||||
|
email: 'user1@example.com',
|
||||||
|
password: 'password1',
|
||||||
|
name: 'User One',
|
||||||
|
);
|
||||||
|
final user2 = UserCreate(
|
||||||
|
email: 'user2@example.com',
|
||||||
|
password: 'password2',
|
||||||
|
name: 'User Two',
|
||||||
|
);
|
||||||
|
|
||||||
|
await userRepository.create(user1).run();
|
||||||
|
await userRepository.create(user2).run();
|
||||||
|
|
||||||
|
final result = await userRepository.findAll().run();
|
||||||
|
|
||||||
|
result.match(
|
||||||
|
(_) => fail('Result should be right'),
|
||||||
|
(users) {
|
||||||
|
print(users);
|
||||||
|
expect(users.length, 2, reason: 'There should be two users');
|
||||||
|
expect(users.map((u) => u.email).toList(),
|
||||||
|
containsAll([user1.email, user2.email]));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user