diff --git a/CHANGELOG.md b/CHANGELOG.md
index c69404b..e99b64f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.7
+
+* Added `when` and `setValidator`
+
## 0.0.5
* Added must and mustWith
diff --git a/README.md b/README.md
index f236087..508856f 100644
--- a/README.md
+++ b/README.md
@@ -71,12 +71,12 @@ void main() {
final user = UserModel(email: 'test@example.com', password: 'Passw0rd!', age: 25);
final validator = UserValidator();
- final errors = validator.validate(user);
+ final result = validator.validate(user);
- if (errors.isEmpty) {
+ if (result.isValid) {
print('User is valid');
} else {
- print('Validation errors: \${errors.map((e) => e.message).join(', ')}');
+ print('Validation errors: \${result.errors.map((e) => e.message).join(', ')}');
}
}
```
@@ -169,14 +169,114 @@ You can apply CascadeMode to your validation chain using the cascaded method:
.mustHaveSpecialCharacter()
```
+## When condition
+
+Adds a conditional execution rule for the validation logic based on the given [condition].
+
+The `when` method allows you to specify a condition that must be met for the validation rules
+within this builder to be executed. If the condition is not met, the validation rules areskipped,
+and the property is considered valid by default.
+
+This is particularly useful for scenarios where certain validation rules should only apply
+under specific circumstances, such as when a certain property is set to a particular value.
+
+[condition] is a function that takes the entire entity and returns a boolean indicating whether
+the validation rules should be applied.
+
+Example:
+
+```dart
+ruleFor((user) => user.phoneNumber, key: 'phoneNumber')
+ .when((user) => user.requiresPhoneNumber)
+ .must((value) => value.isNotEmpty, 'Phone number is required', 'phone_required')
+ .must((value) => value.length == 10, 'Phone number must be 10 digits', 'phone_length');
+```
+
+In the example above, the phone number validation rules are only applied if the user's`requiresPhoneNumber`
+property is true. If the condition is false, the phone number field will be considered valid,and the
+associated rules will not be executed.
+
+## Complex Validations
+
+When working with complex models that contain nested objects, it’s often necessary to apply validation rules not only to the parent model but also to its nested properties. The `setValidator` method allows you to integrate a nested `LucidValidator` within another validator, enabling a modular and scalable approach to validation.
+
+See this example:
+```dart
+// Models
+class Customer {
+ String name;
+ Address address;
+
+ Customer({
+ required this.name,
+ required this.address,
+ });
+}
+
+class Address {
+ String country;
+ String postcode;
+
+ Address({
+ required this.country,
+ required this.postcode,
+ });
+}
+
+```
+
+Now, we can create two validators, `CustomerValidator` and `AddressValidator`.
+Use `setValidator` to integrate `AddressValidor` into `CustomerValidator`;
+
+```dart
+class AddressValidator extends LucidValidator
{
+ AddressValidator() {
+ ruleFor((address) => address.country, key: 'country') //
+ .notEmpty();
+
+ ruleFor((address) => address.postcode, key: 'postcode') //
+ .notEmpty();
+ }
+}
+
+class CustomerValidator extends LucidValidator {
+ final addressValidator = AddressValidator();
+
+ CustomerValidator() {
+ ruleFor((customer) => customer.name, key: 'name') //
+ .notEmpty();
+
+ ruleFor((customer) => customer.address, key: 'address') //
+ .setValidator(addressValidator);
+ }
+}
+```
+
+After that, execute a validation normaly:
+
+```dart
+ var customer = Customer(
+ name: 'John Doe',
+ address: Address(
+ country: 'Brazil',
+ postcode: '12345-678',
+ ),
+ );
+
+ final validator = CustomerValidator();
+
+ var result = validator.validate(customer);
+ expect(result.isValid, isTrue);
+```
+
## Creating Custom Rules
-You can easily extend the functionality of `LucidValidation` by creating your own custom rules using `extensions`. Here’s an example of how to create a validation for phone numbers:
+You can easily extend the functionality of `LucidValidator` by creating your own custom rules using `extensions`. Here’s an example of how to create a validation for phone numbers:
```dart
-extension CustomValidPhoneValidator on LucidValidationBuilder {
- LucidValidationBuilder customValidPhone({String message = 'Invalid phone number format'}) {
+extension CustomValidPhoneValidator on SimpleValidationBuilder {
+ SimpleValidationBuilder customValidPhone({String message = 'Invalid phone number format'}) {
return matchesPattern(
r'^\(?(\d{2})\)?\s?9?\d{4}-?\d{4}\$',
message,
@@ -185,8 +285,8 @@ extension CustomValidPhoneValidator on LucidValidationBuilder {
}
}
-extension CustomValidPasswordValidator on LucidValidationBuilder {
- LucidValidationBuilder customValidPassword() {
+extension CustomValidPasswordValidator on SimpleValidationBuilder {
+ SimpleValidationBuilder customValidPassword() {
return notEmpty()
.minLength(8)
.mustHaveLowercase()
diff --git a/example/lib/domain/validations/extensions.dart b/example/lib/domain/validations/extensions.dart
index 1eec2a1..a2fb1c8 100644
--- a/example/lib/domain/validations/extensions.dart
+++ b/example/lib/domain/validations/extensions.dart
@@ -1,7 +1,7 @@
import 'package:lucid_validation/lucid_validation.dart';
-extension CustomValidPasswordValidator on LucidValidationBuilder {
- LucidValidationBuilder customValidPassword() {
+extension CustomValidPasswordValidator on SimpleValidationBuilder {
+ SimpleValidationBuilder customValidPassword() {
return notEmpty() //
.minLength(5)
.mustHaveLowercase()
@@ -11,8 +11,12 @@ extension CustomValidPasswordValidator on LucidValidationBuilder {
- LucidValidationBuilder customValidPhone(String message) {
- return must((value) => RegExp(r'^\(?(\d{2})\)?\s?9?\d{4}-?\d{4}$').hasMatch(value), message, 'invalid_phone');
+extension CustomValidPhoneValidator on SimpleValidationBuilder {
+ SimpleValidationBuilder customValidPhone(String message) {
+ return matchesPattern(
+ r'^\(?(\d{2})\)?\s?9?\d{4}-?\d{4}$',
+ message: message,
+ code: 'invalid_phone',
+ );
}
}
diff --git a/example/lib/presentation/register_page/register_page.dart b/example/lib/presentation/register_page/register_page.dart
index 1fcaa5f..90b7fb5 100644
--- a/example/lib/presentation/register_page/register_page.dart
+++ b/example/lib/presentation/register_page/register_page.dart
@@ -40,13 +40,13 @@ class _RegisterPageState extends State {
}
void signIn() {
- final errors = validator.validate(registerParamDto);
+ final result = validator.validate(registerParamDto);
- if (errors.isEmpty) {
+ if (result.isValid) {
/// call to api passing the parameter loginParamDto
ScaffoldMessenger.of(context).showSnackBar(sucessSnackBar());
} else {
- ScaffoldMessenger.of(context).showSnackBar(failureSnackBar(errors.first.message));
+ ScaffoldMessenger.of(context).showSnackBar(failureSnackBar(result.errors.first.message));
}
}
@@ -104,10 +104,10 @@ class _RegisterPageState extends State {
ListenableBuilder(
listenable: registerParamDto,
builder: (context, child) {
- final errors = validator.validate(registerParamDto);
+ final result = validator.validate(registerParamDto);
return ElevatedButton(
- onPressed: errors.isEmpty ? signIn : null,
+ onPressed: result.isValid ? signIn : null,
child: const Text('Register'),
);
},
diff --git a/example/pubspec.lock b/example/pubspec.lock
index c1ef826..003ad8d 100644
--- a/example/pubspec.lock
+++ b/example/pubspec.lock
@@ -79,18 +79,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
- sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
+ sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev"
source: hosted
- version: "10.0.4"
+ version: "10.0.5"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
- sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
+ sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev"
source: hosted
- version: "3.0.3"
+ version: "3.0.5"
leak_tracker_testing:
dependency: transitive
description:
@@ -113,7 +113,7 @@ packages:
path: ".."
relative: true
source: path
- version: "0.0.5"
+ version: "0.0.6"
matcher:
dependency: transitive
description:
@@ -126,18 +126,18 @@ packages:
dependency: transitive
description:
name: material_color_utilities
- sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
+ sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
- version: "0.8.0"
+ version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
- sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
+ sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev"
source: hosted
- version: "1.12.0"
+ version: "1.15.0"
path:
dependency: transitive
description:
@@ -195,10 +195,10 @@ packages:
dependency: transitive
description:
name: test_api
- sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
+ sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev"
source: hosted
- version: "0.7.0"
+ version: "0.7.2"
vector_math:
dependency: transitive
description:
@@ -211,10 +211,10 @@ packages:
dependency: transitive
description:
name: vm_service
- sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
+ sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
url: "https://pub.dev"
source: hosted
- version: "14.2.1"
+ version: "14.2.5"
sdks:
dart: ">=3.4.3 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"
diff --git a/lib/lucid_validation.dart b/lib/lucid_validation.dart
index abb87f3..d5b9ab6 100644
--- a/lib/lucid_validation.dart
+++ b/lib/lucid_validation.dart
@@ -54,6 +54,7 @@
///
library lucid_validation;
+export 'src/lucid_validation_builder.dart';
export 'src/lucid_validator.dart';
export 'src/types/types.dart';
export 'src/validations/validations.dart';
diff --git a/lib/src/lucid_validation_builder.dart b/lib/src/lucid_validation_builder.dart
index 75e14ac..163c45d 100644
--- a/lib/src/lucid_validation_builder.dart
+++ b/lib/src/lucid_validation_builder.dart
@@ -1,4 +1,4 @@
-part of 'lucid_validator.dart';
+import '../lucid_validation.dart';
/// Defines the behavior of rule execution when a validation failure occurs.
///
@@ -45,17 +45,23 @@ enum CascadeMode {
/// Builder class used to define validation rules for a specific property type [TProp].
///
/// [TProp] represents the type of the property being validated.
-typedef RuleFunc = ValidatorResult Function(dynamic value, dynamic entity);
+typedef RuleFunc = ValidationError? Function(Entity entity);
-class LucidValidationBuilder {
+typedef SimpleValidationBuilder = LucidValidationBuilder;
+
+abstract class LucidValidationBuilder {
final String key;
- final List> _rules = [];
+ final TProp Function(Entity entity) _selector;
+ final List> _rules = [];
var _mode = CascadeMode.continueExecution;
+ LucidValidator? _nestedValidator;
+
+ bool Function(Entity entity)? _condition;
/// Creates a [LucidValidationBuilder] instance with an optional [key].
///
/// The [key] can be used to identify this specific validation in a larger validation context.
- LucidValidationBuilder({this.key = ''});
+ LucidValidationBuilder(this.key, this._selector);
/// Registers a validation rule for the property.
///
@@ -70,14 +76,17 @@ class LucidValidationBuilder {
/// builder.must((username) => username.isNotEmpty, 'Username cannot be empty');
/// ```
LucidValidationBuilder must(bool Function(TProp value) validator, String message, String code) {
- ValidatorResult callback(value, entity) => ValidatorResult(
- isValid: validator(value),
- error: ValidatorError(
- message: message,
- key: key,
- code: code,
- ),
- );
+ ValidationError? callback(entity) {
+ final value = _selector(entity);
+ if (validator(value)) {
+ return null;
+ }
+ return ValidationError(
+ message: message,
+ key: key,
+ code: code,
+ );
+ }
_rules.add(callback);
@@ -110,14 +119,18 @@ class LucidValidationBuilder {
String message,
String code,
) {
- ValidatorResult callback(value, entity) => ValidatorResult(
- isValid: validator(value, entity),
- error: ValidatorError(
- message: message,
- key: key,
- code: code,
- ),
- );
+ ValidationError? callback(entity) {
+ final value = _selector(entity);
+ if (validator(value, entity)) {
+ return null;
+ }
+
+ return ValidationError(
+ message: message,
+ key: key,
+ code: code,
+ );
+ }
_rules.add(callback);
@@ -150,4 +163,82 @@ class LucidValidationBuilder {
_mode = mode;
return this;
}
+
+ /// Allows the integration of another `LucidValidator` to validate nested properties.
+ ///
+ /// The `setValidator` method enables you to nest another `LucidValidator` within the current validation context.
+ /// This is particularly useful when dealing with complex models that contain nested objects or properties.
+ /// By setting a nested validator, you can apply validation rules to the properties of the nested object
+ /// within the context of the parent object.
+ ///
+ /// [validator] is an instance of `LucidValidator` that will be applied to the nested property.
+ ///
+ /// Example:
+ ///
+ /// ```dart
+ /// .ruleFor((user) => user.address, key: 'address')
+ /// .setValidator(AddressValidator()); // Integrating the nested validator
+ ///
+ /// ```
+ void setValidator(LucidValidator validator) {
+ _nestedValidator = validator;
+ }
+
+ /// Adds a conditional execution rule for the validation logic based on the given [condition].
+ ///
+ /// The `when` method allows you to specify a condition that must be met for the validation rules
+ /// within this builder to be executed. If the condition is not met, the validation rules are skipped,
+ /// and the property is considered valid by default.
+ ///
+ /// This is particularly useful for scenarios where certain validation rules should only apply
+ /// under specific circumstances, such as when a certain property is set to a particular value.
+ ///
+ /// [condition] is a function that takes the entire entity and returns a boolean indicating whether
+ /// the validation rules should be applied.
+ ///
+ /// Example:
+ ///
+ /// ```dart
+ /// ruleFor((user) => user.phoneNumber, key: 'phoneNumber')
+ /// .when((user) => user.requiresPhoneNumber)
+ /// .must((value) => value.isNotEmpty, 'Phone number is required', 'phone_required')
+ /// .must((value) => value.length == 10, 'Phone number must be 10 digits', 'phone_length');
+ /// ```
+ ///
+ /// In the example above, the phone number validation rules are only applied if the user's `requiresPhoneNumber`
+ /// property is true. If the condition is false, the phone number field will be considered valid, and the
+ /// associated rules will not be executed.
+ LucidValidationBuilder when(bool Function(Entity entity) condition) {
+ _condition = condition;
+ return this;
+ }
+
+ /// Executes all validation rules associated with this property and returns a list of [ValidationError]s.
+ List executeRules(Entity entity) {
+ final byPass = _condition?.call(entity) ?? true;
+ if (!byPass) {
+ return [];
+ }
+
+ final errors = [];
+
+ if (_nestedValidator != null) {
+ final nestedErrors = _nestedValidator!.validate(_selector(entity)).errors;
+ errors.addAll(nestedErrors);
+ } else {
+ for (var rule in _rules) {
+ final error = rule(entity);
+
+ if (error != null) {
+ errors.add(error);
+
+ if (_mode == CascadeMode.stopOnFirstFailure) {
+ break;
+ }
+ }
+ }
+ }
+
+ return errors;
+ }
}
diff --git a/lib/src/lucid_validator.dart b/lib/src/lucid_validator.dart
index e6de712..7d24a7a 100644
--- a/lib/src/lucid_validator.dart
+++ b/lib/src/lucid_validator.dart
@@ -1,19 +1,10 @@
import '../lucid_validation.dart';
-part 'lucid_validation_builder.dart';
-
-class _PropSelector {
- final TProp Function(E entity) selector;
- final LucidValidationBuilder builder;
-
- _PropSelector({required this.selector, required this.builder});
-}
-
/// Abstract class for creating validation logic for a specific entity type [E].
///
/// [E] represents the type of the entity being validated.
abstract class LucidValidator {
- final List<_PropSelector> _propSelectors = [];
+ final List> _builders = [];
/// Registers a validation rule for a specific property of the entity.
///
@@ -27,11 +18,9 @@ abstract class LucidValidator {
/// final validator = UserValidation();
/// validator.ruleFor((user) => user.email).validEmail();
/// ```
- LucidValidationBuilder ruleFor(TProp Function(E entity) func, {String key = ''}) {
- final builder = LucidValidationBuilder(key: key);
- final propSelector = _PropSelector(selector: func, builder: builder);
-
- _propSelectors.add(propSelector);
+ LucidValidationBuilder ruleFor(TProp Function(E entity) selector, {String key = ''}) {
+ final builder = _LucidValidationBuilder(key, selector);
+ _builders.add(builder);
return builder;
}
@@ -46,31 +35,27 @@ abstract class LucidValidator {
/// final emailValidator = validator.byField('email');
/// String? validationResult = emailValidator('user@example.com');
/// ```
- String? Function([String?])? byField(E entity, String key) {
- final propSelector = _propSelectors
+ String? Function([String?]) byField(E entity, String key) {
+ final builder = _builders
.where(
- (propSelector) => propSelector.builder.key == key,
+ (builder) => builder.key == key,
)
.firstOrNull;
- if (propSelector == null) return null;
+ if (builder == null) {
+ return ([_]) => null;
+ }
return ([_]) {
- final builder = propSelector.builder;
- final value = propSelector.selector(entity);
- final rules = builder._rules.cast>();
- for (var rule in rules) {
- final result = rule(value, entity);
-
- if (!result.isValid) {
- return result.error.message;
- }
+ final errors = builder.executeRules(entity);
+ if (errors.isNotEmpty) {
+ return errors.first.message;
}
return null;
};
}
- /// Validates the entire entity [E] and returns a list of [ValidatorError]s if any rules fail.
+ /// Validates the entire entity [E] and returns a list of [ValidationError]s if any rules fail.
///
/// This method iterates through all registered rules and checks if the entity meets all of them.
///
@@ -84,25 +69,18 @@ abstract class LucidValidator {
/// print('Validation failed: ${errors.map((e) => e.message).join(', ')}');
/// }
/// ```
- List validate(E entity) {
- final List errors = [];
-
- for (var propSelector in _propSelectors) {
- final propValue = propSelector.selector(entity);
- final mode = propSelector.builder._mode;
-
- for (var rule in propSelector.builder._rules) {
- final result = rule(propValue, entity);
-
- if (!result.isValid) {
- errors.add(result.error);
- if (mode == CascadeMode.stopOnFirstFailure) {
- break;
- }
- }
- }
- }
-
- return errors;
+ ValidationResult validate(E entity) {
+ final errors = _builders.fold([], (previousErrors, errors) {
+ return previousErrors..addAll(errors.executeRules(entity));
+ });
+
+ return ValidationResult(
+ isValid: errors.isEmpty,
+ errors: errors,
+ );
}
}
+
+class _LucidValidationBuilder extends LucidValidationBuilder {
+ _LucidValidationBuilder(super.key, super.selector);
+}
diff --git a/lib/src/types/types.dart b/lib/src/types/types.dart
index d423c7c..3b7f539 100644
--- a/lib/src/types/types.dart
+++ b/lib/src/types/types.dart
@@ -1,2 +1,2 @@
-export 'validator_error.dart';
-export 'validator_result.dart';
+export 'validation_error.dart';
+export 'validation_result.dart';
diff --git a/lib/src/types/validator_error.dart b/lib/src/types/validation_error.dart
similarity index 80%
rename from lib/src/types/validator_error.dart
rename to lib/src/types/validation_error.dart
index 97b3582..8c7d76e 100644
--- a/lib/src/types/validator_error.dart
+++ b/lib/src/types/validation_error.dart
@@ -1,8 +1,8 @@
/// Represents an error that occurs during validation.
///
-/// [ValidatorError] provides details about the validation error, including
+/// [ValidationError] provides details about the validation error, including
/// an optional key that identifies which field or property the error is associated with.
-class ValidatorError {
+class ValidationError {
/// The error message describing what went wrong during validation.
final String message;
@@ -12,11 +12,11 @@ class ValidatorError {
/// An optional code that identifies the specific validation error.
final String code;
- /// Constructs a [ValidatorError].
+ /// Constructs a [ValidationError].
///
/// [message] provides a description of the error.
/// [key] optionally identifies the field or property related to the error.
- const ValidatorError({
+ const ValidationError({
required this.message,
required this.code,
this.key = '',
diff --git a/lib/src/types/validation_result.dart b/lib/src/types/validation_result.dart
new file mode 100644
index 0000000..eb5ccc2
--- /dev/null
+++ b/lib/src/types/validation_result.dart
@@ -0,0 +1,22 @@
+import 'validation_error.dart';
+
+/// Represents the result of a validation rule.
+///
+/// [ValidationResult] encapsulates whether the validation was successful
+/// and, if not, provides the associated [ValidationError].
+class ValidationResult {
+ /// Indicates whether the validation was successful.
+ final bool isValid;
+
+ /// Provides details about the validation error if the validation failed.
+ final List errors;
+
+ /// Constructs a [ValidationResult].
+ ///
+ /// [isValid] specifies whether the validation passed or failed.
+ /// [errors] provides the errors details in case of a validation failure.
+ const ValidationResult({
+ required this.isValid,
+ required this.errors,
+ });
+}
diff --git a/lib/src/types/validator_result.dart b/lib/src/types/validator_result.dart
deleted file mode 100644
index 032319e..0000000
--- a/lib/src/types/validator_result.dart
+++ /dev/null
@@ -1,22 +0,0 @@
-import 'validator_error.dart';
-
-/// Represents the result of a validation rule.
-///
-/// [ValidatorResult] encapsulates whether the validation was successful
-/// and, if not, provides the associated [ValidatorError].
-class ValidatorResult {
- /// Indicates whether the validation was successful.
- final bool isValid;
-
- /// Provides details about the validation error if the validation failed.
- final ValidatorError error;
-
- /// Constructs a [ValidatorResult].
- ///
- /// [isValid] specifies whether the validation passed or failed.
- /// [error] provides the error details in case of a validation failure.
- const ValidatorResult({
- required this.isValid,
- required this.error,
- });
-}
diff --git a/pubspec.yaml b/pubspec.yaml
index e7717fd..6f88ecf 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@ description: "A Dart/Flutter package for building strongly typed validation rule
repository: https://github.com/Flutterando/lucid_validation
homepage: https://pub.dev/documentation/lucid_validation/latest/
-version: 0.0.6
+version: 0.0.7
environment:
sdk: ">=3.0.0 <4.0.0"
diff --git a/test/lucid_validation_test.dart b/test/lucid_validation_test.dart
index e236fe1..5b93277 100644
--- a/test/lucid_validation_test.dart
+++ b/test/lucid_validation_test.dart
@@ -12,7 +12,8 @@ void main() {
phone: '(11) 99999-9999',
);
- final errors = validator.validate(userEntity);
+ final result = validator.validate(userEntity);
+ final errors = result.errors;
expect(errors.length, 2);
expect(errors.first.key, 'email');
@@ -29,7 +30,8 @@ void main() {
phone: '(11) 99999-9999',
);
- final errors = validator.validate(userEntity);
+ final result = validator.validate(userEntity);
+ final errors = result.errors;
expect(errors.length, 6);
expect(errors.first.key, 'password');
@@ -50,7 +52,8 @@ void main() {
phone: '(11) 99999-9999',
);
- final errors = validator.validate(userEntity);
+ final result = validator.validate(userEntity);
+ final errors = result.errors;
expect(errors.length, 1);
expect(errors.first.key, 'age');
@@ -66,7 +69,8 @@ void main() {
phone: '',
);
- final errors = validator.validate(userEntity);
+ final result = validator.validate(userEntity);
+ final errors = result.errors;
expect(errors.length, 1);
expect(errors.first.key, 'phone');
@@ -82,7 +86,8 @@ void main() {
phone: '',
);
- final errors = validator.validate(userEntity);
+ final result = validator.validate(userEntity);
+ final errors = result.errors;
expect(errors.length, 10);
expect(
@@ -97,15 +102,46 @@ void main() {
confirmPassword: '123asdASD@',
password: '123asdASD@',
);
- final registerValidator = CredentialsRegisterValidator();
+ final validator = CredentialsRegisterValidator();
- var errors = registerValidator.validate(credentials);
+ var result = validator.validate(credentials);
+ var errors = result.errors;
expect(errors.length, 0);
credentials = credentials.copyWith(confirmPassword: '123asdASDsdsdw');
- errors = registerValidator.validate(credentials);
-
+ result = validator.validate(credentials);
+ errors = result.errors;
expect(errors.length, 2);
+
+ final stringError = validator.byField(credentials, 'confirmPassword')();
+ expect(stringError, 'Must be equal to password');
+ });
+
+ test('setValidator', () {
+ var customer = Customer(
+ name: 'John Doe',
+ address: Address(
+ country: 'Brazil',
+ postcode: '12345-678',
+ ),
+ );
+
+ final validator = CustomerValidator();
+
+ var result = validator.validate(customer);
+ expect(result.isValid, isTrue);
+
+ customer.address = Address(
+ country: 'Brazil',
+ postcode: '',
+ );
+
+ result = validator.validate(customer);
+
+ expect(result.isValid, isFalse);
+
+ final stringError = validator.byField(customer, 'address')();
+ expect(stringError, 'Cannot be empty');
});
}
diff --git a/test/mocks/mocks.dart b/test/mocks/mocks.dart
index 3f4bc8b..8d6f494 100644
--- a/test/mocks/mocks.dart
+++ b/test/mocks/mocks.dart
@@ -93,3 +93,45 @@ class CredentialsRegisterValidator extends LucidValidator {
.equalTo((entity) => entity.password, message: 'Must be equal to password');
}
}
+
+class Address {
+ String country;
+ String postcode;
+
+ Address({
+ required this.country,
+ required this.postcode,
+ });
+}
+
+class AddressValidator extends LucidValidator {
+ AddressValidator() {
+ ruleFor((address) => address.country, key: 'country') //
+ .notEmpty();
+
+ ruleFor((address) => address.postcode, key: 'postcode') //
+ .notEmpty();
+ }
+}
+
+class Customer {
+ String name;
+ Address address;
+
+ Customer({
+ required this.name,
+ required this.address,
+ });
+}
+
+class CustomerValidator extends LucidValidator {
+ final addressValidator = AddressValidator();
+
+ CustomerValidator() {
+ ruleFor((customer) => customer.name, key: 'name') //
+ .notEmpty();
+
+ ruleFor((customer) => customer.address, key: 'address') //
+ .setValidator(addressValidator);
+ }
+}