blob: a142e820e9e47e6fbca8029180a6a77fc3226fe3 [file] [log] [blame]
/**
* This package contains matches to write tests for parsers.
*
* Examples:
*
* var json = new JsonParser();
*
* // verifies that the input gets parsed and all input is consumed
* expect('{"a": 1}', accepts(new JsonParser()));
*
* // verifies that the input gets parsed to a dictionary and that all input is consumed
* expect('{"a": 1}', parses(new JsonParser(), {'a': 1}));
*/
library test_util;
import 'package:matcher/matcher.dart';
import 'package:petitparser/petitparser.dart';
/**
* Returns a matcher that succeeds if the [parser] accepts the input.
*/
Matcher accept(Parser parser) {
return new _Accept(parser);
}
class _Accept extends Matcher {
final Parser parser;
_Accept(this.parser);
bool matches(item, Map matchState) => parser.accept(item);
Description describe(Description description) {
return description.add('$parser to accept input');
}
}
/**
* Returns a matcher that succeeds if the [parser] results in [matcher].
*/
Matcher parse(Parser parser, matcher, [int position = -1]) {
return new _Parse(parser, wrapMatcher(matcher), position);
}
class _Parse extends Matcher {
final Parser parser;
final Matcher matcher;
final int position;
_Parse(this.parser, this.matcher, this.position);
bool matches(item, Map matchState) {
Result result = parser.parse(item);
if (!matcher.matches(result.value, matchState)) {
addStateInfo(matchState, {'property': 'value', 'result': result});
return false;
}
if (position >= 0 &&
!equals(position).matches(result.position, matchState)) {
addStateInfo(matchState, {'property': 'position', 'result': result});
return false;
}
return true;
}
Description describe(Description description) {
return description.add('$parser to accept ').addDescriptionOf(matcher);
}
Description describeMismatch(
item, Description mismatchDescription, Map matchState, bool verbose) {
mismatchDescription
.add('has parse result ')
.add('"${matchState['result']}"');
if (matchState['property'] == 'value') {
mismatchDescription.add(' which parse result ');
var subDescription = new StringDescription();
matcher.describeMismatch(matchState['result'].value, subDescription,
matchState['state'], verbose);
if (subDescription.length > 0) {
mismatchDescription.add(subDescription.toString());
} else {
mismatchDescription.add('doesn\'t match');
matcher.describe(mismatchDescription);
}
return mismatchDescription;
} else if (matchState['property'] == 'position') {
mismatchDescription
.add(' that consumes input to ')
.add(matchState['result'].position.toString())
.add(' instead of ')
.add(position.toString());
return mismatchDescription;
}
throw new Exception('Internal matcher error');
}
}