Skip to content

Commit 00b0578

Browse files
committed
Built new unit tests for validators.
1 parent 52b285f commit 00b0578

File tree

2 files changed

+266
-32
lines changed

2 files changed

+266
-32
lines changed

lib/src/form_builder_validators.dart

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class FormBuilderValidators {
6363
}) {
6464
return (valueCandidate) {
6565
if (valueCandidate != null) {
66+
assert(valueCandidate is num || valueCandidate is String);
6667
final number = valueCandidate is num
6768
? valueCandidate
6869
: num.tryParse(valueCandidate.toString());
@@ -87,6 +88,7 @@ class FormBuilderValidators {
8788
}) {
8889
return (valueCandidate) {
8990
if (valueCandidate != null) {
91+
assert(valueCandidate is num || valueCandidate is String);
9092
final number = valueCandidate is num
9193
? valueCandidate
9294
: num.tryParse(valueCandidate.toString());
@@ -108,7 +110,9 @@ class FormBuilderValidators {
108110
bool allowEmpty = false,
109111
String errorText,
110112
}) {
113+
assert(minLength > 0);
111114
return (valueCandidate) {
115+
assert(null == valueCandidate || valueCandidate is String);
112116
final valueLength = valueCandidate?.length ?? 0;
113117
if (valueLength < minLength && (!allowEmpty || valueLength > 0)) {
114118
return errorText ??
@@ -125,10 +129,15 @@ class FormBuilderValidators {
125129
num maxLength, {
126130
String errorText,
127131
}) {
132+
assert(maxLength > 0);
128133
return (valueCandidate) {
129-
if (valueCandidate != null && valueCandidate.length > maxLength) {
130-
return errorText ??
131-
FormBuilderLocalizations.of(context).maxLengthErrorText(maxLength);
134+
if (null != valueCandidate) {
135+
assert(valueCandidate is String);
136+
if (valueCandidate.length > maxLength) {
137+
return errorText ??
138+
FormBuilderLocalizations.of(context)
139+
.maxLengthErrorText(maxLength);
140+
}
132141
}
133142
return null;
134143
};
@@ -140,8 +149,9 @@ class FormBuilderValidators {
140149
String errorText,
141150
}) {
142151
return (valueCandidate) {
143-
if (valueCandidate != null && valueCandidate.isNotEmpty) {
144-
if (!isEmail(valueCandidate.trim())) {
152+
if (null != valueCandidate) {
153+
assert(valueCandidate is String);
154+
if (valueCandidate.isNotEmpty && !isEmail(valueCandidate.trim())) {
145155
return errorText ??
146156
FormBuilderLocalizations.of(context).emailErrorText;
147157
}
@@ -162,14 +172,16 @@ class FormBuilderValidators {
162172
List<String> hostBlacklist = const [],
163173
}) {
164174
return (valueCandidate) {
165-
if (valueCandidate != null && valueCandidate.isNotEmpty) {
166-
if (!isURL(valueCandidate,
167-
protocols: protocols,
168-
requireTld: requireTld,
169-
requireProtocol: requireProtocol,
170-
allowUnderscore: allowUnderscore,
171-
hostWhitelist: hostWhitelist,
172-
hostBlacklist: hostBlacklist)) {
175+
if (null != valueCandidate) {
176+
assert(valueCandidate is String);
177+
if (valueCandidate.isNotEmpty &&
178+
!isURL(valueCandidate,
179+
protocols: protocols,
180+
requireTld: requireTld,
181+
requireProtocol: requireProtocol,
182+
allowUnderscore: allowUnderscore,
183+
hostWhitelist: hostWhitelist,
184+
hostBlacklist: hostBlacklist)) {
173185
return errorText ?? FormBuilderLocalizations.of(context).urlErrorText;
174186
}
175187
}
@@ -184,8 +196,10 @@ class FormBuilderValidators {
184196
String errorText,
185197
}) {
186198
return (valueCandidate) {
187-
if (valueCandidate != null && valueCandidate.isNotEmpty) {
188-
if (!RegExp(pattern).hasMatch(valueCandidate)) {
199+
if (null != valueCandidate) {
200+
assert(valueCandidate is String);
201+
if (valueCandidate.isNotEmpty &&
202+
!RegExp(pattern).hasMatch(valueCandidate)) {
189203
return errorText ??
190204
FormBuilderLocalizations.of(context).matchErrorText;
191205
}
@@ -200,9 +214,12 @@ class FormBuilderValidators {
200214
String errorText,
201215
}) {
202216
return (valueCandidate) {
203-
if (valueCandidate.isNotEmpty && num.tryParse(valueCandidate) == null) {
204-
return errorText ??
205-
FormBuilderLocalizations.of(context).numericErrorText;
217+
if (null != valueCandidate) {
218+
assert(valueCandidate is String);
219+
if (valueCandidate.isNotEmpty && num.tryParse(valueCandidate) == null) {
220+
return errorText ??
221+
FormBuilderLocalizations.of(context).numericErrorText;
222+
}
206223
}
207224
return null;
208225
};
@@ -215,10 +232,13 @@ class FormBuilderValidators {
215232
int radix,
216233
}) {
217234
return (valueCandidate) {
218-
if (valueCandidate.isNotEmpty &&
219-
int.tryParse(valueCandidate, radix: radix) == null) {
220-
return errorText ??
221-
FormBuilderLocalizations.of(context).numericErrorText;
235+
if (null != valueCandidate) {
236+
assert(valueCandidate is String);
237+
if (valueCandidate.isNotEmpty &&
238+
int.tryParse(valueCandidate, radix: radix) == null) {
239+
return errorText ??
240+
FormBuilderLocalizations.of(context).numericErrorText;
241+
}
222242
}
223243
return null;
224244
};
@@ -231,10 +251,13 @@ class FormBuilderValidators {
231251
String errorText,
232252
}) {
233253
return (valueCandidate) {
234-
if (valueCandidate.isNotEmpty &&
235-
double.tryParse(valueCandidate) == null) {
236-
return errorText ??
237-
FormBuilderLocalizations.of(context).numericErrorText;
254+
if (null != valueCandidate) {
255+
assert(valueCandidate is String);
256+
if (valueCandidate.isNotEmpty &&
257+
double.tryParse(valueCandidate) == null) {
258+
return errorText ??
259+
FormBuilderLocalizations.of(context).numericErrorText;
260+
}
238261
}
239262
return null;
240263
};
@@ -246,8 +269,9 @@ class FormBuilderValidators {
246269
String errorText,
247270
}) {
248271
return (valueCandidate) {
249-
if (valueCandidate != null && valueCandidate.isNotEmpty) {
250-
if (!isCreditCard(valueCandidate)) {
272+
if (null != valueCandidate) {
273+
assert(valueCandidate is String);
274+
if (valueCandidate.isNotEmpty && !isCreditCard(valueCandidate)) {
251275
return errorText ??
252276
FormBuilderLocalizations.of(context).creditCardErrorText;
253277
}
@@ -265,8 +289,9 @@ class FormBuilderValidators {
265289
String errorText,
266290
}) {
267291
return (valueCandidate) {
268-
if (valueCandidate != null && valueCandidate.isNotEmpty) {
269-
if (!isIP(valueCandidate, version)) {
292+
if (null != valueCandidate) {
293+
assert(valueCandidate is String);
294+
if (valueCandidate.isNotEmpty && !isIP(valueCandidate, version)) {
270295
return errorText ?? FormBuilderLocalizations.of(context).ipErrorText;
271296
}
272297
}
@@ -280,8 +305,9 @@ class FormBuilderValidators {
280305
String errorText,
281306
}) {
282307
return (valueCandidate) {
283-
if (valueCandidate != null && valueCandidate.isNotEmpty) {
284-
if (!isDate(valueCandidate)) {
308+
if (null != valueCandidate) {
309+
assert(valueCandidate is String);
310+
if (valueCandidate.isNotEmpty && !isDate(valueCandidate)) {
285311
return errorText ??
286312
FormBuilderLocalizations.of(context).dateStringErrorText;
287313
}
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import 'package:flutter/cupertino.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:flutter_localizations/flutter_localizations.dart';
4+
import 'package:flutter_test/flutter_test.dart';
5+
import 'package:flutter_form_builder/flutter_form_builder.dart';
6+
7+
/// Test Harness for running Validations
8+
Future<void> testValidations(
9+
WidgetTester tester, void Function(BuildContext) validations) async {
10+
await tester.pumpWidget(MaterialApp(
11+
localizationsDelegates: [
12+
FormBuilderLocalizations.delegate,
13+
GlobalMaterialLocalizations.delegate,
14+
GlobalWidgetsLocalizations.delegate,
15+
],
16+
home: Builder(
17+
builder: (BuildContext context) {
18+
// Exercise validations using the provided context
19+
validations(context);
20+
// The builder function must return a widget.
21+
return Placeholder();
22+
},
23+
),
24+
));
25+
26+
// Critical to pumpAndSettle to let Builder build to exercise validations
27+
await tester.pumpAndSettle();
28+
}
29+
30+
void main() {
31+
testWidgets(
32+
'FormBuilderValidators.required',
33+
(WidgetTester tester) => testValidations(tester, (context) {
34+
final validator = FormBuilderValidators.required(context);
35+
// Pass
36+
expect(validator(false), isNull);
37+
expect(validator(0), isNull);
38+
expect(validator('0'), isNull);
39+
expect(validator('something long'), isNull);
40+
expect(validator(DateTime.now()), isNull);
41+
// Fail
42+
expect(validator(null), isNotNull);
43+
expect(validator(''), isNotNull);
44+
expect(validator([]), isNotNull);
45+
}));
46+
47+
testWidgets(
48+
'FormBuilderValidators.maxLength',
49+
(WidgetTester tester) => testValidations(tester, (context) {
50+
final validator = FormBuilderValidators.maxLength(context, 5);
51+
// Pass
52+
expect(validator(null), isNull);
53+
expect(validator(''), isNull);
54+
expect(validator('two'), isNull);
55+
expect(validator('12345'), isNull);
56+
// Fail
57+
expect(validator('something long'), isNotNull);
58+
expect(validator('123456'), isNotNull);
59+
}));
60+
testWidgets(
61+
'FormBuilderValidators.minLength',
62+
(WidgetTester tester) => testValidations(tester, (context) {
63+
final validator = FormBuilderValidators.minLength(context, 5);
64+
// Pass
65+
expect(validator('12345'), isNull);
66+
expect(validator('123456'), isNull);
67+
expect(validator('something long'), isNull);
68+
// Fail
69+
expect(validator(null), isNotNull);
70+
expect(validator(''), isNotNull);
71+
expect(validator('two'), isNotNull);
72+
// Advanced
73+
final validatorAllowEmpty =
74+
FormBuilderValidators.minLength(context, 5, allowEmpty: true);
75+
expect(validatorAllowEmpty(null), isNull);
76+
expect(validatorAllowEmpty(''), isNull);
77+
}));
78+
79+
testWidgets(
80+
'FormBuilderValidators.email',
81+
(WidgetTester tester) => testValidations(tester, (context) {
82+
final validator = FormBuilderValidators.email(context);
83+
// Pass
84+
expect(validator(null), isNull);
85+
expect(validator(''), isNull);
86+
expect(validator('[email protected]'), isNull);
87+
expect(validator(' [email protected] '), isNull);
88+
expect(validator('[email protected] '), isNull);
89+
expect(validator(' [email protected]'), isNull);
90+
// Fail
91+
expect(validator('john@flutter'), isNotNull);
92+
expect(validator('john@ flutter.dev'), isNotNull);
93+
expect(validator('john flutter.dev'), isNotNull);
94+
expect(validator('flutter.dev'), isNotNull);
95+
}));
96+
97+
testWidgets(
98+
'FormBuilderValidators.max',
99+
(WidgetTester tester) => testValidations(tester, (context) {
100+
final validator = FormBuilderValidators.max(context, 20);
101+
// Pass
102+
expect(validator(null), isNull);
103+
expect(validator(''), isNull);
104+
expect(validator(0), isNull);
105+
expect(validator(-1), isNull);
106+
expect(validator(-1.1), isNull);
107+
expect(validator(1.2), isNull);
108+
expect(validator('19'), isNull);
109+
expect(validator('20'), isNull);
110+
expect(validator(20), isNull);
111+
// Fail
112+
expect(validator(20.01), isNotNull);
113+
expect(validator(21), isNotNull);
114+
expect(validator('21'), isNotNull);
115+
expect(validator(999), isNotNull);
116+
}));
117+
118+
testWidgets(
119+
'FormBuilderValidators.min',
120+
(WidgetTester tester) => testValidations(tester, (context) {
121+
final validator = FormBuilderValidators.min(context, 30);
122+
// Pass
123+
expect(validator(null), isNull);
124+
expect(validator(''), isNull);
125+
expect(validator(30.01), isNull);
126+
expect(validator(31), isNull);
127+
expect(validator('31'), isNull);
128+
expect(validator(70), isNull);
129+
// Fail
130+
expect(validator(-1), isNotNull);
131+
expect(validator(0), isNotNull);
132+
expect(validator('10'), isNotNull);
133+
expect(validator(10), isNotNull);
134+
expect(validator(29), isNotNull);
135+
}));
136+
137+
testWidgets(
138+
'FormBuilderValidators.numeric',
139+
(WidgetTester tester) => testValidations(tester, (context) {
140+
final validator = FormBuilderValidators.numeric(context);
141+
// Pass
142+
expect(validator(null), isNull);
143+
expect(validator(''), isNull);
144+
expect(validator('0'), isNull);
145+
expect(validator('31'), isNull);
146+
expect(validator('-1'), isNull);
147+
expect(validator('-1.01'), isNull);
148+
// Fail
149+
expect(validator('A'), isNotNull);
150+
expect(validator('XYZ'), isNotNull);
151+
}));
152+
153+
testWidgets(
154+
'FormBuilderValidators.url',
155+
(WidgetTester tester) => testValidations(tester, (context) {
156+
final validator = FormBuilderValidators.url(context);
157+
// Pass
158+
expect(validator(null), isNull);
159+
expect(validator(''), isNull);
160+
expect(validator('https://www.google.com'), isNull);
161+
expect(validator('www.google.com'), isNull);
162+
expect(validator('google.com'), isNull);
163+
expect(validator('http://google.com'), isNull);
164+
// Fail
165+
expect(validator('.com'), isNotNull);
166+
// Advanced overrides
167+
expect(
168+
FormBuilderValidators.url(context,
169+
protocols: ['https', 'http'],
170+
errorText:
171+
'Only HTTP and HTTPS allowed')('ftp://www.google.com'),
172+
isNotNull);
173+
}));
174+
175+
testWidgets(
176+
'FormBuilderValidators.IP',
177+
(WidgetTester tester) => testValidations(tester, (context) {
178+
final validator = FormBuilderValidators.IP(context);
179+
// Pass
180+
expect(validator(null), isNull);
181+
expect(validator(''), isNull);
182+
expect(validator('192.168.0.1'), isNull);
183+
// Fail
184+
expect(validator('256.168.0.1'), isNotNull);
185+
expect(validator('256.168.0.'), isNotNull);
186+
expect(validator('255.168.0.'), isNotNull);
187+
}));
188+
189+
testWidgets(
190+
'FormBuilderValidators.compose',
191+
(WidgetTester tester) => testValidations(tester, (context) {
192+
final validator = FormBuilderValidators.compose([
193+
FormBuilderValidators.required(context),
194+
FormBuilderValidators.numeric(context),
195+
FormBuilderValidators.minLength(context, 2),
196+
FormBuilderValidators.maxLength(context, 3),
197+
]);
198+
// Pass
199+
expect(validator('12'), isNull);
200+
expect(validator('123'), isNull);
201+
// Fail
202+
expect(validator(null), isNotNull);
203+
expect(validator(''), isNotNull);
204+
expect(validator('1'), isNotNull);
205+
expect(validator('1234'), isNotNull);
206+
expect(validator('ABC'), isNotNull);
207+
}));
208+
}

0 commit comments

Comments
 (0)