Skip to content

Commit 071f3f5

Browse files
implement isDateTime validator tests
1 parent b1e0dc9 commit 071f3f5

File tree

3 files changed

+151
-2
lines changed

3 files changed

+151
-2
lines changed

example/lib/new_api_examples/api_refactoring_main.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class NewAPIHomePage extends StatelessWidget {
5454
validator:
5555
FormBuilderValidators.compose(<FormFieldValidator<String>>[
5656
isReq(
57-
isNum(max(70), isNumMsg: 'La edad debe ser numérica.'),
57+
isNum(max(70), 'La edad debe ser numérica.'),
5858
),
5959

6060
/// Include your own custom `FormFieldValidator` function, if you want
@@ -112,7 +112,7 @@ class NewAPIHomePage extends StatelessWidget {
112112
return null;
113113
},
114114
]),
115-
isNumMsg: 'La edad debe ser numérica.',
115+
'La edad debe ser numérica.',
116116
),
117117
),
118118
),

lib/new_api_prototype/core_validators/type_validators.dart

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,45 @@ Validator<T> isBool<T extends Object>(
144144
}
145145
return (false, null);
146146
}
147+
148+
/// This function returns a validator that checks if the user input is either a `DateTime`
149+
/// or a parsable String to `DateTime`.
150+
/// If it checks positive, then it returns null when `next` is not provided.
151+
/// Otherwise, if `next` is provided, it passes the transformed value as `String`
152+
/// to the `next` validator.
153+
///
154+
/// ## Caveats
155+
/// - If the user input is a String, the validator tries to parse it using the
156+
/// [DateTime.tryParse] method (which parses a subset of ISO 8601 date specifications),
157+
/// thus, it cannot be adapted to parse only some specific DateTime pattern.
158+
Validator<T> isDateTime<T extends Object>([
159+
Validator<DateTime>? next,
160+
String? isDateTimeMsg,
161+
]) {
162+
String? finalValidator(T value) {
163+
final (bool isValid, DateTime? typeTransformedValue) =
164+
_isDateTimeValidateAndConvert(value);
165+
if (!isValid) {
166+
return isDateTimeMsg ??
167+
// This error text is not 100% correct for this validator. It also validates non-Strings.
168+
FormBuilderLocalizations.current.dateStringErrorText;
169+
}
170+
return next?.call(typeTransformedValue!);
171+
}
172+
173+
return finalValidator;
174+
}
175+
176+
(bool, DateTime?) _isDateTimeValidateAndConvert<T extends Object>(T value) {
177+
if (value is DateTime) {
178+
return (true, value);
179+
}
180+
181+
if (value is String) {
182+
final DateTime? transformedValue = DateTime.tryParse(value);
183+
if (transformedValue != null) {
184+
return (true, transformedValue);
185+
}
186+
}
187+
return (false, null);
188+
}

test/new_api_testing/core_validators/type_validators_test.dart

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ void main() {
88
String? isEven(int input) => input % 2 == 0 ? null : errorMsg;
99
String? greaterThan9(num input) => input > 9 ? null : errorMsg;
1010
String? isT(bool input) => input ? null : errorMsg;
11+
String? isLaterThan1995(DateTime input) =>
12+
input.year > 1995 ? null : errorMsg;
1113

1214
group('Validator: isString', () {
1315
test('Should only check if the input is a String', () {
@@ -171,4 +173,109 @@ void main() {
171173
expect(v(false), isNull);
172174
});
173175
});
176+
177+
group('Validator: isDateTime', () {
178+
test('Should only check if the input is an DateTime/parsable to DateTime',
179+
() {
180+
final Validator<Object> v = isDateTime();
181+
182+
expect(v('not an DateTime'),
183+
equals(FormBuilderLocalizations.current.dateStringErrorText));
184+
expect(v('1/2.0/2023.0'),
185+
equals(FormBuilderLocalizations.current.dateStringErrorText));
186+
expect(v(123.0),
187+
equals(FormBuilderLocalizations.current.dateStringErrorText));
188+
189+
expect(
190+
v('1992-04-20'),
191+
isNull,
192+
reason: 'Valid date in YYYY-MM-DD format (1992-04-20)',
193+
);
194+
expect(
195+
v('2012-02-27'),
196+
isNull,
197+
reason: 'Valid date in YYYY-MM-DD format (2012-02-27)',
198+
);
199+
expect(
200+
v('2012-02-27 13:27:00'),
201+
isNull,
202+
reason: 'Valid datetime with time in YYYY-MM-DD HH:MM:SS format',
203+
);
204+
expect(
205+
v('2012-02-27 13:27:00.123456789z'),
206+
isNull,
207+
reason: 'Valid datetime with fractional seconds and Z suffix',
208+
);
209+
expect(
210+
v('2012-02-27 13:27:00,123456789z'),
211+
isNull,
212+
reason:
213+
'Valid datetime with fractional seconds using comma and Z suffix',
214+
);
215+
expect(
216+
v('20120227 13:27:00'),
217+
isNull,
218+
reason: 'Valid compact date and time in YYYYMMDD HH:MM:SS format',
219+
);
220+
expect(
221+
v('20120227T132700'),
222+
isNull,
223+
reason:
224+
'Valid compact datetime with T separator in YYYYMMDDTHHMMSS format',
225+
);
226+
expect(
227+
v('20120227'),
228+
isNull,
229+
reason: 'Valid compact date in YYYYMMDD format',
230+
);
231+
expect(
232+
v('+20120227'),
233+
isNull,
234+
reason: 'Valid date with plus sign in +YYYYMMDD format',
235+
);
236+
expect(
237+
v('2012-02-27T14Z'),
238+
isNull,
239+
reason: 'Valid datetime with time and Z suffix',
240+
);
241+
expect(
242+
v('2012-02-27T14+00:00'),
243+
isNull,
244+
reason: 'Valid datetime with time and timezone offset +00:00',
245+
);
246+
expect(
247+
v('-123450101 00:00:00 Z'),
248+
isNull,
249+
reason: 'Valid historical date with negative year -12345 and Z suffix',
250+
);
251+
expect(
252+
v('2002-02-27T14:00:00-0500'),
253+
isNull,
254+
reason:
255+
'Valid datetime with timezone offset -0500, equivalent to "2002-02-27T19:00:00Z"',
256+
);
257+
expect(
258+
v(DateTime.now()),
259+
isNull,
260+
reason: 'Current DateTime object is valid',
261+
);
262+
});
263+
test('Should check if the input is a DateTime with year later than 1995',
264+
() {
265+
final Validator<Object> v = isDateTime(isLaterThan1995);
266+
267+
expect(v('not a datetime'),
268+
equals(FormBuilderLocalizations.current.dateStringErrorText));
269+
expect(v('12330803'), equals(errorMsg));
270+
});
271+
272+
test('Should check if the input is a DateTime using custom error', () {
273+
const String customError = 'custom error';
274+
final Validator<Object> v = isDateTime(null, customError);
275+
276+
expect(v('not datetime'), equals(customError));
277+
expect(v('1289-02-12'), isNull);
278+
expect(v(DateTime(1990)), isNull);
279+
});
280+
});
174281
}

0 commit comments

Comments
 (0)