Skip to content

Commit

Permalink
TW-2046 Added unit tests for compositeNameVaidator and verifyNameInte…
Browse files Browse the repository at this point in the history
…ractor
  • Loading branch information
KhaledNjim committed Nov 18, 2024
1 parent d6ba8e5 commit c95ec5f
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 8 deletions.
2 changes: 1 addition & 1 deletion lib/domain/app_state/validator/verify_name_view_state.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:fluffychat/presentation/state/failure.dart';
import 'package:fluffychat/presentation/state/success.dart';

class VerifyNameViewState extends UIState {}
class VerifyNameSuccessViewState extends UIState {}

class VerifyNameFailure extends FeatureFailure {
const VerifyNameFailure(dynamic exception) : super(exception: exception);
Expand Down
5 changes: 5 additions & 0 deletions lib/domain/exception/verify_name_exception.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:equatable/equatable.dart';

abstract class VerifyNameException extends Equatable implements Exception {
static const nameWithOnlySpace = 'The name cannot contain only spaces';
static const emptyName = 'The name cannot be empty';

final String? message;
const VerifyNameException(this.message);
Expand All @@ -14,3 +15,7 @@ class NameWithSpaceOnlyException extends VerifyNameException {
const NameWithSpaceOnlyException()
: super(VerifyNameException.nameWithOnlySpace);
}

class EmptyNameException extends VerifyNameException {
const EmptyNameException() : super(VerifyNameException.emptyName);
}
2 changes: 1 addition & 1 deletion lib/domain/model/extensions/list_validator_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ extension ListValidatorExtension on List<Validator> {
return either;
}
}
return Right<Failure, Success>(VerifyNameViewState());
return Right<Failure, Success>(VerifyNameSuccessViewState());
}
}
5 changes: 3 additions & 2 deletions lib/domain/model/extensions/validator_failure_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';

extension ValidatorFailureExtension on VerifyNameFailure {
String getMessage(BuildContext context) {
if (exception is NameWithSpaceOnlyException) {
return L10n.of(context)!.this_field_cannot_be_blank;
if (exception is NameWithSpaceOnlyException ||
exception is EmptyNameException) {
return L10n.of(context)!.thisFieldCannotBeBlank;
} else {
return '';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ class CompositeNameValidator extends Validator<NewNameRequest> {
Either<Failure, Success> validate(NewNameRequest value) {
return _listValidator.isNotEmpty
? _listValidator.getValidatorNameViewState(value)
: Right<Failure, Success>(VerifyNameViewState());
: Right<Failure, Success>(VerifyNameSuccessViewState());
}
}
20 changes: 20 additions & 0 deletions lib/domain/model/verification/empty_name_validator.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:dartz/dartz.dart';
import 'package:fluffychat/app_state/failure.dart';
import 'package:fluffychat/app_state/success.dart';
import 'package:fluffychat/domain/app_state/validator/verify_name_view_state.dart';
import 'package:fluffychat/domain/exception/verify_name_exception.dart';
import 'package:fluffychat/domain/model/verification/new_name_request.dart';
import 'package:fluffychat/domain/model/verification/validator.dart';

class EmptyNameValidator extends Validator<NewNameRequest> {
@override
Either<Failure, Success> validate(NewNameRequest value) {
if (value.value == null || value.value!.isEmpty) {
return const Left<Failure, Success>(
VerifyNameFailure(EmptyNameException()),
);
} else {
return Right<Failure, Success>(VerifyNameSuccessViewState());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class NameWithSpaceOnlyValidator extends Validator<NewNameRequest> {
VerifyNameFailure(NameWithSpaceOnlyException()),
);
} else {
return Right<Failure, Success>(VerifyNameViewState());
return Right<Failure, Success>(VerifyNameSuccessViewState());
}
}
}
7 changes: 5 additions & 2 deletions lib/pages/chat_details/chat_details_edit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:fluffychat/domain/app_state/room/update_group_chat_success.dart'
import 'package:fluffychat/domain/app_state/room/upload_content_state.dart';
import 'package:fluffychat/domain/app_state/validator/verify_name_view_state.dart';
import 'package:fluffychat/domain/model/extensions/validator_failure_extension.dart';
import 'package:fluffychat/domain/model/verification/empty_name_validator.dart';
import 'package:fluffychat/domain/model/verification/name_with_space_only_validator.dart';
import 'package:fluffychat/domain/usecase/room/update_group_chat_interactor.dart';
import 'package:fluffychat/domain/usecase/room/upload_content_for_web_interactor.dart';
Expand Down Expand Up @@ -450,8 +451,10 @@ class ChatDetailsEditController extends State<ChatDetailsEdit>
}

String? getErrorMessage(String content) {
return verifyNameInteractor
.execute(content, [NameWithSpaceOnlyValidator()]).fold(
return verifyNameInteractor.execute(
content,
[EmptyNameValidator(), NameWithSpaceOnlyValidator()],
).fold(
(failure) {
if (failure is VerifyNameFailure) {
return failure.getMessage(context);
Expand Down
73 changes: 73 additions & 0 deletions test/domain/model/verification/composite_name_validator_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import 'package:dartz/dartz.dart';
import 'package:fluffychat/domain/model/verification/composite_name_validator.dart';
import 'package:fluffychat/domain/model/verification/validator.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:fluffychat/app_state/failure.dart';
import 'package:fluffychat/app_state/success.dart';
import 'package:fluffychat/domain/app_state/validator/verify_name_view_state.dart';
import 'package:fluffychat/domain/model/verification/new_name_request.dart';
import 'composite_name_validator_test.mocks.dart';

@GenerateMocks([Validator])
void main() {
group('CompositeNameValidator', () {
late CompositeNameValidator compositeValidator;
late MockValidator mockValidator1;
late MockValidator mockValidator2;
setUp(() {
compositeValidator = CompositeNameValidator([]);
mockValidator1 = MockValidator();
mockValidator2 = MockValidator();
});
test('returns VerifyNameViewState when list of validators is empty', () {
final newNameRequest = NewNameRequest('ValidName');

final result = compositeValidator.validate(newNameRequest);

expect(result, isA<Right>());
expect(result, Right<Failure, Success>(VerifyNameSuccessViewState()));
});

test(
'applies multiple validators and returns failure if any validator fails',
() {
final newNameRequest = NewNameRequest('InvalidName');

when(mockValidator1.validate(newNameRequest))
.thenReturn(Right(VerifyNameSuccessViewState()));
when(mockValidator2.validate(newNameRequest))
.thenReturn(const Left(VerifyNameFailure("Invalid name")));

final compositeValidator =
CompositeNameValidator([mockValidator1, mockValidator2]);

final result = compositeValidator.validate(newNameRequest);

expect(result, isA<Left>());
verify(mockValidator1.validate(newNameRequest)).called(1);
verify(mockValidator2.validate(newNameRequest)).called(1);
});

test('returns success if all validators pass', () {
final mockValidator1 = MockValidator();
final mockValidator2 = MockValidator();
final newNameRequest = NewNameRequest('ValidName');

when(mockValidator1.validate(newNameRequest))
.thenReturn(Right(VerifyNameSuccessViewState()));
when(mockValidator2.validate(newNameRequest))
.thenReturn(Right(VerifyNameSuccessViewState()));

final compositeValidator =
CompositeNameValidator([mockValidator1, mockValidator2]);

final result = compositeValidator.validate(newNameRequest);

expect(result, isA<Right>());
verify(mockValidator1.validate(newNameRequest)).called(1);
verify(mockValidator2.validate(newNameRequest)).called(1);
});
});
}
72 changes: 72 additions & 0 deletions test/domain/usecase/verify_name_interactor_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import 'package:dartz/dartz.dart';
import 'package:fluffychat/domain/usecase/verify_name_interactor.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:fluffychat/app_state/failure.dart';
import 'package:fluffychat/app_state/success.dart';
import 'package:fluffychat/domain/app_state/validator/verify_name_view_state.dart';

import '../model/verification/composite_name_validator_test.mocks.dart';

void main() {
group('VerifyNameInteractor', () {
late MockValidator mockValidator1;
late MockValidator mockValidator2;
late VerifyNameInteractor interactor;
setUp(() {
mockValidator1 = MockValidator();
mockValidator2 = MockValidator();
interactor = VerifyNameInteractor();
});
test('returns VerifyNameViewState success when all validators pass', () {
const newName = 'ValidName';

when(mockValidator1.validate(any))
.thenReturn(Right(VerifyNameSuccessViewState()));
when(mockValidator2.validate(any))
.thenReturn(Right(VerifyNameSuccessViewState()));

final result =
interactor.execute(newName, [mockValidator1, mockValidator2]);

expect(result, isA<Right>());
expect(result, Right<Failure, Success>(VerifyNameSuccessViewState()));
verify(mockValidator1.validate(any)).called(1);
verify(mockValidator2.validate(any)).called(1);
});

test('returns failure when one of the validators fails', () {
final mockValidator1 = MockValidator();
final mockValidator2 = MockValidator();
final interactor = VerifyNameInteractor();
const newName = 'InvalidName';

when(mockValidator1.validate(any))
.thenReturn(Right(VerifyNameSuccessViewState()));
when(mockValidator2.validate(any))
.thenReturn(const Left(VerifyNameFailure('Name is not valid')));

final result =
interactor.execute(newName, [mockValidator1, mockValidator2]);

expect(result, isA<Left>());
verify(mockValidator1.validate(any)).called(1);
verify(mockValidator2.validate(any)).called(1);
});

test('returns VerifyNameFailure when an exception occurs', () {
final mockValidator = MockValidator();
final interactor = VerifyNameInteractor();
const newName = 'ValidName';

// Mock a validator to throw an exception
when(mockValidator.validate(any))
.thenThrow(Exception('Validation failed'));

final result = interactor.execute(newName, [mockValidator]);

expect(result, isA<Left>());
expect((result as Left).value, isA<VerifyNameFailure>());
});
});
}

0 comments on commit c95ec5f

Please sign in to comment.