Apply pedantic
This commit is contained in:
parent
f7188f8a62
commit
5d8c2ae005
12 changed files with 106 additions and 94 deletions
30
README.md
30
README.md
|
@ -36,7 +36,7 @@ For convenience's sake, this library also exports `matcher`.
|
|||
import 'package:angel_validate/angel_validate.dart';
|
||||
|
||||
main() {
|
||||
var validator = new Validator({
|
||||
var validator = Validator({
|
||||
'username': isAlphaNum,
|
||||
'multiple,keys,with,same,rules': [isString, isNotEmpty],
|
||||
'balance': [
|
||||
|
@ -91,7 +91,7 @@ to throw an error if it is not present.
|
|||
|
||||
```dart
|
||||
main() {
|
||||
var validator = new Validator({
|
||||
var validator = Validator({
|
||||
'googleId*': isString,
|
||||
|
||||
// You can also use `requireField`
|
||||
|
@ -111,7 +111,7 @@ If not present, default values will be filled in *before* validation.
|
|||
This means that they can still be used with required fields.
|
||||
|
||||
```dart
|
||||
final Validator todo = new Validator({
|
||||
final Validator todo = Validator({
|
||||
'text*': isString,
|
||||
'completed*': isBool
|
||||
}, defaultValues: {
|
||||
|
@ -134,9 +134,9 @@ The function must *synchronously* return a `bool`.
|
|||
|
||||
```dart
|
||||
main() {
|
||||
var validator = new Validator({
|
||||
var validator = Validator({
|
||||
'key*': (key) {
|
||||
var file = new File('whitelist.txt');
|
||||
var file = File('whitelist.txt');
|
||||
return file.readFileSync().contains(key);
|
||||
}
|
||||
});
|
||||
|
@ -148,7 +148,7 @@ If these are not present, `angel_validate` will *attempt* to generate
|
|||
a coherent error message on its own.
|
||||
|
||||
```dart
|
||||
new Validator({
|
||||
Validator({
|
||||
'age': [greaterThanOrEqualTo(18)]
|
||||
}, customErrorMessages: {
|
||||
'age': 'You must be an adult to see this page.'
|
||||
|
@ -189,7 +189,7 @@ You can also use `extend` to mark fields as required or forbidden that originall
|
|||
were not. Default value and custom error message extension is also supported.
|
||||
|
||||
```dart
|
||||
final Validator userValidator = new Validator({
|
||||
final Validator userValidator = Validator({
|
||||
'username': isString,
|
||||
'age': [
|
||||
isNum,
|
||||
|
@ -210,7 +210,7 @@ var ageIsOptional = userValidator.extend({
|
|||
});
|
||||
```
|
||||
|
||||
Note that by default, new validation rules are simply appended to
|
||||
Note that by default, validation rules are simply appended to
|
||||
the existing list. To completely overwrite existing rules, set the
|
||||
`overwrite` flag to `true`.
|
||||
|
||||
|
@ -246,23 +246,23 @@ a `Validator` instance to the constructor, because it extends the
|
|||
|
||||
```dart
|
||||
main() {
|
||||
var bio = new Validator({
|
||||
var bio = Validator({
|
||||
'age*': [isInt, greaterThanOrEqualTo(0)],
|
||||
'birthYear*': isInt,
|
||||
'countryOfOrigin': isString
|
||||
});
|
||||
|
||||
var book = new Validator({
|
||||
var book = Validator({
|
||||
'title*': isString,
|
||||
'year*': [
|
||||
isNum,
|
||||
(year) {
|
||||
return year <= new DateTime.now().year;
|
||||
return year <= DateTime.now().year;
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var author = new Validator({
|
||||
var author = Validator({
|
||||
'bio*': bio,
|
||||
'books*': [
|
||||
isList,
|
||||
|
@ -289,11 +289,11 @@ main() {
|
|||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_validate/server.dart';
|
||||
|
||||
final Validator echo = new Validator({
|
||||
final Validator echo = Validator({
|
||||
'message*': (String message) => message.length >= 5
|
||||
});
|
||||
|
||||
final Validator todo = new Validator({
|
||||
final Validator todo = Validator({
|
||||
'text*': isString,
|
||||
'completed*': isBool
|
||||
}, defaultValues: {
|
||||
|
@ -301,7 +301,7 @@ final Validator todo = new Validator({
|
|||
});
|
||||
|
||||
main() async {
|
||||
var app = new Angel();
|
||||
var app = Angel();
|
||||
|
||||
app.chain([validate(echo)]).post('/echo', (req, res) async {
|
||||
res.write('You said: "${req.bodyAsMap["message"]}"');
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
include: package:pedantic/analysis_options.yaml
|
||||
analyzer:
|
||||
strong-mode:
|
||||
implicit-casts: false
|
|
@ -1,24 +1,24 @@
|
|||
import 'package:angel_validate/angel_validate.dart';
|
||||
|
||||
main() {
|
||||
var bio = new Validator({
|
||||
var bio = Validator({
|
||||
'age*': [isInt, greaterThanOrEqualTo(0)],
|
||||
'birthYear*': isInt,
|
||||
'countryOfOrigin': isString
|
||||
});
|
||||
|
||||
var book = new Validator({
|
||||
var book = Validator({
|
||||
'title*': isString,
|
||||
'year*': [
|
||||
isNum,
|
||||
(year) {
|
||||
return year <= new DateTime.now().year;
|
||||
return year <= DateTime.now().year;
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// ignore: unused_local_variable
|
||||
var author = new Validator({
|
||||
var author = Validator({
|
||||
'bio*': bio,
|
||||
'books*': [isList, everyElement(book)]
|
||||
}, defaultValues: {
|
||||
|
|
|
@ -52,13 +52,13 @@ RequestHandler filterQuery(Iterable<String> only) {
|
|||
/// Validates the data in `req.bodyAsMap`, and sets the body to
|
||||
/// filtered data before continuing the response.
|
||||
RequestHandler validate(Validator validator,
|
||||
{String errorMessage: 'Invalid data.'}) {
|
||||
{String errorMessage = 'Invalid data.'}) {
|
||||
return (RequestContext req, res) async {
|
||||
await req.parseBody();
|
||||
var result = await asyncApplyValidator(validator, req.bodyAsMap, req.app);
|
||||
|
||||
if (result.errors.isNotEmpty) {
|
||||
throw new AngelHttpException.badRequest(
|
||||
throw AngelHttpException.badRequest(
|
||||
message: errorMessage, errors: result.errors);
|
||||
}
|
||||
|
||||
|
@ -73,13 +73,13 @@ RequestHandler validate(Validator validator,
|
|||
/// Validates the data in `req.queryParameters`, and sets the query to
|
||||
/// filtered data before continuing the response.
|
||||
RequestHandler validateQuery(Validator validator,
|
||||
{String errorMessage: 'Invalid data.'}) {
|
||||
{String errorMessage = 'Invalid data.'}) {
|
||||
return (RequestContext req, res) async {
|
||||
var result =
|
||||
await asyncApplyValidator(validator, req.queryParameters, req.app);
|
||||
|
||||
if (result.errors.isNotEmpty) {
|
||||
throw new AngelHttpException.badRequest(
|
||||
throw AngelHttpException.badRequest(
|
||||
message: errorMessage, errors: result.errors);
|
||||
}
|
||||
|
||||
|
@ -94,13 +94,13 @@ RequestHandler validateQuery(Validator validator,
|
|||
/// Validates the data in `e.data`, and sets the data to
|
||||
/// filtered data before continuing the service event.
|
||||
HookedServiceEventListener validateEvent(Validator validator,
|
||||
{String errorMessage: 'Invalid data.'}) {
|
||||
{String errorMessage = 'Invalid data.'}) {
|
||||
return (HookedServiceEvent e) async {
|
||||
var result = await asyncApplyValidator(
|
||||
validator, e.data as Map, (e.request?.app ?? e.service.app));
|
||||
|
||||
if (result.errors.isNotEmpty) {
|
||||
throw new AngelHttpException.badRequest(
|
||||
throw AngelHttpException.badRequest(
|
||||
message: errorMessage, errors: result.errors);
|
||||
}
|
||||
|
||||
|
@ -120,7 +120,7 @@ Future<ValidationResult> asyncApplyValidator(
|
|||
|
||||
for (var key in result.data.keys) {
|
||||
var value = result.data[key];
|
||||
var description = new StringDescription("'$key': expected ");
|
||||
var description = StringDescription("'$key': expected ");
|
||||
|
||||
for (var rule in validator.rules[key]) {
|
||||
if (rule is AngelMatcher) {
|
||||
|
@ -135,7 +135,7 @@ Future<ValidationResult> asyncApplyValidator(
|
|||
}
|
||||
}
|
||||
|
||||
var m = new Map<String, dynamic>.from(result.data);
|
||||
var m = Map<String, dynamic>.from(result.data);
|
||||
for (var key in errantKeys) {
|
||||
m.remove(key);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import 'context_aware.dart';
|
|||
AngelMatcher predicateWithAngel(
|
||||
FutureOr<bool> Function(String, Object, Angel) f,
|
||||
[String description = 'satisfies function']) =>
|
||||
new _PredicateWithAngel(f, description);
|
||||
_PredicateWithAngel(f, description);
|
||||
|
||||
/// Returns an [AngelMatcher] that applies an asynchronously-created [Matcher]
|
||||
/// to the input.
|
||||
|
@ -19,7 +19,7 @@ AngelMatcher predicateWithAngel(
|
|||
/// Use this to match values against configuration, injections, etc.
|
||||
AngelMatcher matchWithAngel(FutureOr<Matcher> Function(Object, Map, Angel) f,
|
||||
[String description = 'satisfies asynchronously created matcher']) =>
|
||||
new _MatchWithAngel(f, description);
|
||||
_MatchWithAngel(f, description);
|
||||
|
||||
/// Calls [matchWithAngel] without the initial parameter.
|
||||
AngelMatcher matchWithAngelBinary(
|
||||
|
@ -42,7 +42,7 @@ AngelMatcher matchWithAngelNullary(FutureOr<Matcher> Function() f,
|
|||
/// If [x] is an [AngelMatcher], then it is returned, unmodified.
|
||||
AngelMatcher wrapAngelMatcher(x) {
|
||||
if (x is AngelMatcher) return x;
|
||||
if (x is ContextAwareMatcher) return new _WrappedAngelMatcher(x);
|
||||
if (x is ContextAwareMatcher) return _WrappedAngelMatcher(x);
|
||||
return wrapAngelMatcher(wrapContextAwareMatcher(x));
|
||||
}
|
||||
|
||||
|
@ -50,13 +50,13 @@ AngelMatcher wrapAngelMatcher(x) {
|
|||
AngelMatcher matchAsync(FutureOr<Matcher> Function(String, Object) matcher,
|
||||
FutureOr Function() feature,
|
||||
[String description = 'satisfies asynchronously created matcher']) {
|
||||
return new _MatchAsync(matcher, feature, description);
|
||||
return _MatchAsync(matcher, feature, description);
|
||||
}
|
||||
|
||||
/// Returns an [AngelMatcher] that verifies that an item with the given [idField]
|
||||
/// exists in the service at [servicePath], without throwing a `404` or returning `null`.
|
||||
AngelMatcher idExistsInService(String servicePath,
|
||||
{String idField: 'id', String description}) {
|
||||
{String idField = 'id', String description}) {
|
||||
return predicateWithAngel(
|
||||
(key, item, app) async {
|
||||
try {
|
||||
|
@ -115,7 +115,7 @@ class _MatchWithAngel extends AngelMatcher {
|
|||
@override
|
||||
Future<bool> matchesWithAngel(
|
||||
item, String key, Map context, Map matchState, Angel app) {
|
||||
return new Future.sync(() => f(item, context, app)).then((result) {
|
||||
return Future.sync(() => f(item, context, app)).then((result) {
|
||||
return result.matches(item, matchState);
|
||||
});
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ class _PredicateWithAngel extends AngelMatcher {
|
|||
@override
|
||||
Future<bool> matchesWithAngel(
|
||||
item, String key, Map context, Map matchState, Angel app) {
|
||||
return new Future<bool>.sync(() => predicate(key, item, app));
|
||||
return Future<bool>.sync(() => predicate(key, item, app));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,14 +4,14 @@ import 'package:matcher/matcher.dart';
|
|||
ContextAwareMatcher predicateWithContext(
|
||||
bool Function(Object, String, Map, Map) f,
|
||||
[String description = 'satisfies function']) {
|
||||
return new _PredicateWithContext(f, description);
|
||||
return _PredicateWithContext(f, description);
|
||||
}
|
||||
|
||||
/// Wraps [x] in a [ContextAwareMatcher].
|
||||
ContextAwareMatcher wrapContextAwareMatcher(x) {
|
||||
if (x is ContextAwareMatcher)
|
||||
if (x is ContextAwareMatcher) {
|
||||
return x;
|
||||
else if (x is Matcher) return new _WrappedContextAwareMatcher(x);
|
||||
} else if (x is Matcher) return _WrappedContextAwareMatcher(x);
|
||||
return wrapContextAwareMatcher(wrapMatcher(x));
|
||||
}
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@ import 'package:matcher/matcher.dart';
|
|||
import 'context_aware.dart';
|
||||
import 'context_validator.dart';
|
||||
|
||||
final RegExp _alphaDash = new RegExp(r'^[A-Za-z0-9_-]+$');
|
||||
final RegExp _alphaNum = new RegExp(r'^[A-Za-z0-9]+$');
|
||||
final RegExp _email = new RegExp(
|
||||
final RegExp _alphaDash = RegExp(r'^[A-Za-z0-9_-]+$');
|
||||
final RegExp _alphaNum = RegExp(r'^[A-Za-z0-9]+$');
|
||||
final RegExp _email = RegExp(
|
||||
r"^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$");
|
||||
final RegExp _url = new RegExp(
|
||||
final RegExp _url = RegExp(
|
||||
r'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)');
|
||||
|
||||
/// Asserts that a `String` is alphanumeric, but also lets it contain dashes or underscores.
|
||||
|
@ -126,8 +126,8 @@ ContextValidator requiredWithoutAll(Iterable<String> keys) =>
|
|||
_require((ctx) => !keys.any(ctx.containsKey));
|
||||
|
||||
ContextValidator _require(bool Function(Map) f) {
|
||||
return new ContextValidator(
|
||||
return ContextValidator(
|
||||
(key, context) => f(context) && context.containsKey(key),
|
||||
(desc, key, _) => new StringDescription('Missing required field "$key".'),
|
||||
(desc, key, _) => StringDescription('Missing required field "$key".'),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ import 'package:matcher/matcher.dart';
|
|||
import 'context_aware.dart';
|
||||
import 'context_validator.dart';
|
||||
|
||||
final RegExp _asterisk = new RegExp(r'\*$');
|
||||
final RegExp _forbidden = new RegExp(r'!$');
|
||||
final RegExp _optional = new RegExp(r'\?$');
|
||||
final RegExp _asterisk = RegExp(r'\*$');
|
||||
final RegExp _forbidden = RegExp(r'!$');
|
||||
final RegExp _optional = RegExp(r'\?$');
|
||||
|
||||
/// Returns a value based the result of a computation.
|
||||
typedef DefaultValueFunction();
|
||||
|
@ -84,11 +84,12 @@ class Validator extends Matcher {
|
|||
var iterable = [];
|
||||
|
||||
_addTo(x) {
|
||||
if (x is Iterable)
|
||||
if (x is Iterable) {
|
||||
x.forEach(_addTo);
|
||||
else
|
||||
} else {
|
||||
iterable.add(x);
|
||||
}
|
||||
}
|
||||
|
||||
_iterable.forEach(_addTo);
|
||||
|
||||
|
@ -108,8 +109,8 @@ class Validator extends Matcher {
|
|||
Validator.empty();
|
||||
|
||||
Validator(Map<String, dynamic> schema,
|
||||
{Map<String, dynamic> defaultValues: const {},
|
||||
Map<String, dynamic> customErrorMessages: const {}}) {
|
||||
{Map<String, dynamic> defaultValues = const {},
|
||||
Map<String, dynamic> customErrorMessages = const {}}) {
|
||||
this.defaultValues.addAll(defaultValues ?? {});
|
||||
this.customErrorMessages.addAll(customErrorMessages ?? {});
|
||||
_importSchema(schema);
|
||||
|
@ -121,7 +122,7 @@ class Validator extends Matcher {
|
|||
/// Validates, and filters input data.
|
||||
ValidationResult check(Map inputData) {
|
||||
List<String> errors = [];
|
||||
var input = new Map.from(inputData);
|
||||
var input = Map.from(inputData);
|
||||
Map<String, dynamic> data = {};
|
||||
|
||||
for (String key in defaultValues.keys) {
|
||||
|
@ -133,23 +134,25 @@ class Validator extends Matcher {
|
|||
|
||||
for (String field in forbiddenFields) {
|
||||
if (input.containsKey(field)) {
|
||||
if (!customErrorMessages.containsKey(field))
|
||||
if (!customErrorMessages.containsKey(field)) {
|
||||
errors.add("'$field' is forbidden.");
|
||||
else
|
||||
} else {
|
||||
errors.add(customError(field, input[field]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String field in requiredFields) {
|
||||
if (!_hasContextValidators(rules[field] ?? [])) {
|
||||
if (!input.containsKey(field)) {
|
||||
if (!customErrorMessages.containsKey(field))
|
||||
if (!customErrorMessages.containsKey(field)) {
|
||||
errors.add("'$field' is required.");
|
||||
else
|
||||
} else {
|
||||
errors.add(customError(field, 'none'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run context validators.
|
||||
|
||||
|
@ -157,7 +160,7 @@ class Validator extends Matcher {
|
|||
if (key is String && rules.containsKey(key)) {
|
||||
var valid = true;
|
||||
var value = input[key];
|
||||
var description = new StringDescription("'$key': expected ");
|
||||
var description = StringDescription("'$key': expected ");
|
||||
|
||||
for (var matcher in rules[key]) {
|
||||
if (matcher is ContextValidator) {
|
||||
|
@ -192,8 +195,9 @@ class Validator extends Matcher {
|
|||
}
|
||||
|
||||
if (!result) {
|
||||
if (!customErrorMessages.containsKey(key))
|
||||
if (!customErrorMessages.containsKey(key)) {
|
||||
errors.add(matcher.describe(description).toString().trim());
|
||||
}
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
@ -215,10 +219,10 @@ class Validator extends Matcher {
|
|||
}
|
||||
|
||||
if (errors.isNotEmpty) {
|
||||
return new ValidationResult().._errors.addAll(errors);
|
||||
return ValidationResult().._errors.addAll(errors);
|
||||
}
|
||||
|
||||
return new ValidationResult().._data.addAll(data);
|
||||
return ValidationResult().._data.addAll(data);
|
||||
}
|
||||
|
||||
/// Validates, and filters input data after running [autoParse].
|
||||
|
@ -227,29 +231,30 @@ class Validator extends Matcher {
|
|||
|
||||
/// Renders the given custom error.
|
||||
String customError(String key, value) {
|
||||
if (!customErrorMessages.containsKey(key))
|
||||
throw new ArgumentError("No custom error message registered for '$key'.");
|
||||
if (!customErrorMessages.containsKey(key)) {
|
||||
throw ArgumentError("No custom error message registered for '$key'.");
|
||||
}
|
||||
|
||||
var msg = customErrorMessages[key];
|
||||
|
||||
if (msg is String)
|
||||
if (msg is String) {
|
||||
return msg.replaceAll('{{value}}', value.toString());
|
||||
else if (msg is CustomErrorMessageFunction) {
|
||||
} else if (msg is CustomErrorMessageFunction) {
|
||||
return msg(value);
|
||||
}
|
||||
|
||||
throw new ArgumentError("Invalid custom error message '$key': $msg");
|
||||
throw ArgumentError("Invalid custom error message '$key': $msg");
|
||||
}
|
||||
|
||||
/// Validates input data, and throws an error if it is invalid.
|
||||
///
|
||||
/// Otherwise, the filtered data is returned.
|
||||
Map<String, dynamic> enforce(Map inputData,
|
||||
{String errorMessage: 'Invalid data.'}) {
|
||||
{String errorMessage = 'Invalid data.'}) {
|
||||
var result = check(inputData);
|
||||
|
||||
if (result._errors.isNotEmpty) {
|
||||
throw new ValidationException(errorMessage, errors: result._errors);
|
||||
throw ValidationException(errorMessage, errors: result._errors);
|
||||
}
|
||||
|
||||
return result.data;
|
||||
|
@ -263,11 +268,11 @@ class Validator extends Matcher {
|
|||
|
||||
/// Creates a copy with additional validation rules.
|
||||
Validator extend(Map<String, dynamic> schema,
|
||||
{Map<String, dynamic> defaultValues: const {},
|
||||
Map<String, dynamic> customErrorMessages: const {},
|
||||
bool overwrite: false}) {
|
||||
{Map<String, dynamic> defaultValues = const {},
|
||||
Map<String, dynamic> customErrorMessages = const {},
|
||||
bool overwrite = false}) {
|
||||
Map<String, dynamic> _schema = {};
|
||||
var child = new Validator.empty()
|
||||
var child = Validator.empty()
|
||||
..defaultValues.addAll(this.defaultValues)
|
||||
..defaultValues.addAll(defaultValues ?? {})
|
||||
..customErrorMessages.addAll(this.customErrorMessages)
|
||||
|
@ -355,18 +360,18 @@ class ValidationResult {
|
|||
final List<String> _errors = [];
|
||||
|
||||
/// The successfully validated data, filtered from the original input.
|
||||
Map<String, dynamic> get data => new Map<String, dynamic>.unmodifiable(_data);
|
||||
Map<String, dynamic> get data => Map<String, dynamic>.unmodifiable(_data);
|
||||
|
||||
/// A list of errors that resulted in the given data being marked invalid.
|
||||
///
|
||||
/// This is empty if validation was successful.
|
||||
List<String> get errors => new List<String>.unmodifiable(_errors);
|
||||
List<String> get errors => List<String>.unmodifiable(_errors);
|
||||
|
||||
ValidationResult withData(Map<String, dynamic> data) =>
|
||||
new ValidationResult().._data.addAll(data).._errors.addAll(_errors);
|
||||
ValidationResult().._data.addAll(data).._errors.addAll(_errors);
|
||||
|
||||
ValidationResult withErrors(Iterable<String> errors) =>
|
||||
new ValidationResult().._data.addAll(_data).._errors.addAll(errors);
|
||||
ValidationResult().._data.addAll(_data).._errors.addAll(errors);
|
||||
}
|
||||
|
||||
/// Occurs when user-provided data is invalid.
|
||||
|
@ -377,8 +382,8 @@ class ValidationException extends AngelHttpException {
|
|||
/// A descriptive message describing the error.
|
||||
final String message;
|
||||
|
||||
ValidationException(this.message, {List<String> errors: const []})
|
||||
: super(new FormatException(message),
|
||||
ValidationException(this.message, {List<String> errors = const []})
|
||||
: super(FormatException(message),
|
||||
statusCode: 400,
|
||||
errors: errors ?? [],
|
||||
stackTrace: StackTrace.current) {
|
||||
|
|
|
@ -15,4 +15,5 @@ dev_dependencies:
|
|||
build_web_compilers: ^0.4.0
|
||||
logging: ^0.11.0
|
||||
mock_request:
|
||||
pedantic: ^1.0.0
|
||||
test: ^1.0.0
|
|
@ -1,10 +1,10 @@
|
|||
import 'package:angel_validate/angel_validate.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
final Validator emailSchema = new Validator({'to': isEmail},
|
||||
customErrorMessages: {'to': 'Hello, world!'});
|
||||
final Validator emailSchema =
|
||||
Validator({'to': isEmail}, customErrorMessages: {'to': 'Hello, world!'});
|
||||
|
||||
final Validator todoSchema = new Validator({
|
||||
final Validator todoSchema = Validator({
|
||||
'id': [isInt, isPositive],
|
||||
'text*': isString,
|
||||
'completed*': isBool,
|
||||
|
@ -32,7 +32,7 @@ main() {
|
|||
todoSchema
|
||||
.enforce({'id': 'fool', 'text': 'Hello, world!', 'completed': 4});
|
||||
// ignore: deprecated_member_use
|
||||
}, throwsA(new isInstanceOf<ValidationException>()));
|
||||
}, throwsA(isInstanceOf<ValidationException>()));
|
||||
});
|
||||
|
||||
test('filter', () {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_framework/http.dart';
|
||||
|
@ -7,7 +8,7 @@ import 'package:logging/logging.dart';
|
|||
import 'package:mock_request/mock_request.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
final Validator echoSchema = new Validator({'message*': isString});
|
||||
final Validator echoSchema = Validator({'message*': isString});
|
||||
|
||||
void printRecord(LogRecord rec) {
|
||||
print(rec);
|
||||
|
@ -21,8 +22,8 @@ main() {
|
|||
TestClient client;
|
||||
|
||||
setUp(() async {
|
||||
app = new Angel();
|
||||
http = new AngelHttp(app, useZone: false);
|
||||
app = Angel();
|
||||
http = AngelHttp(app, useZone: false);
|
||||
|
||||
app.chain([validate(echoSchema)]).post('/echo',
|
||||
(RequestContext req, res) async {
|
||||
|
@ -30,7 +31,7 @@ main() {
|
|||
res.write('Hello, ${req.bodyAsMap['message']}!');
|
||||
});
|
||||
|
||||
app.logger = new Logger('angel')..onRecord.listen(printRecord);
|
||||
app.logger = Logger('angel')..onRecord.listen(printRecord);
|
||||
client = await connectTo(app);
|
||||
});
|
||||
|
||||
|
@ -51,12 +52,15 @@ main() {
|
|||
});
|
||||
|
||||
test('enforce', () async {
|
||||
var rq = new MockHttpRequest('POST', new Uri(path: '/echo'))
|
||||
var rq = MockHttpRequest('POST', Uri(path: '/echo'))
|
||||
..headers.add('accept', '*/*')
|
||||
..headers.add('content-type', 'application/json')
|
||||
..write(json.encode({'foo': 'bar'}))
|
||||
..close();
|
||||
http.handleRequest(rq);
|
||||
..write(json.encode({'foo': 'bar'}));
|
||||
|
||||
scheduleMicrotask(() async {
|
||||
await rq.close();
|
||||
await http.handleRequest(rq);
|
||||
});
|
||||
|
||||
var responseBody = await rq.response.transform(utf8.decoder).join();
|
||||
print('Response: ${responseBody}');
|
||||
|
|
|
@ -5,7 +5,7 @@ final $errors = querySelector('#errors') as UListElement;
|
|||
final $form = querySelector('#form') as FormElement;
|
||||
final $blank = querySelector('[name="blank"]') as InputElement;
|
||||
|
||||
final Validator formSchema = new Validator({
|
||||
final Validator formSchema = Validator({
|
||||
'firstName*': [isString, isNotEmpty],
|
||||
'lastName*': [isString, isNotEmpty],
|
||||
'age*': [isInt, greaterThanOrEqualTo(18)],
|
||||
|
@ -15,12 +15,13 @@ final Validator formSchema = new Validator({
|
|||
'familySize': 1
|
||||
}, customErrorMessages: {
|
||||
'age': (age) {
|
||||
if (age is int && age < 18)
|
||||
if (age is int && age < 18) {
|
||||
return 'Only adults can register for passports. Sorry, kid!';
|
||||
else if (age == null || (age is String && age.trim().isEmpty))
|
||||
} else if (age == null || (age is String && age.trim().isEmpty)) {
|
||||
return 'Age is required.';
|
||||
else
|
||||
} else {
|
||||
return 'Age must be a positive integer. Unless you are a monster...';
|
||||
}
|
||||
},
|
||||
'blank':
|
||||
"I told you to leave that field blank, but instead you typed '{{value}}'..."
|
||||
|
@ -54,12 +55,12 @@ main() {
|
|||
'Number of People in Family: ${passportInfo["familySize"]}'));
|
||||
} on ValidationException catch (e) {
|
||||
$errors.children.addAll(e.errors.map((error) {
|
||||
return new LIElement()..text = error;
|
||||
return LIElement()..text = error;
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
LIElement success(String str) => new LIElement()
|
||||
LIElement success(String str) => LIElement()
|
||||
..classes.add('success')
|
||||
..text = str;
|
||||
|
|
Loading…
Reference in a new issue