Chromium Code Reviews| Index: lib/unittest/numeric_matchers.dart |
| =================================================================== |
| --- lib/unittest/numeric_matchers.dart (revision 0) |
| +++ lib/unittest/numeric_matchers.dart (revision 0) |
| @@ -0,0 +1,241 @@ |
| +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +/** |
| + * Returns a matcher which matches if the match argument is greater |
| + * than the given [value]. |
| + */ |
| +IMatcher greaterThan(value) => |
| + new _OrderingComparison(value, false, false, true, 'greater than'); |
| + |
| +/** |
| + * Returns a matcher which matches if the match argument is greater |
| + * than or equal to the given [value]. |
| + */ |
| +IMatcher greaterThanOrEqualTo(value) => |
| + new _OrderingComparison(value, true, false, true, 'greater than or equal to'); |
| + |
| +/** |
| + * Returns a matcher which matches if the match argument is less |
| + * than the given [value]. |
| + */ |
| +IMatcher lessThan(value) => |
| + new _OrderingComparison(value, false, true, false, 'less than'); |
| + |
| +/** |
| + * Returns a matcher which matches if the match argument is less |
| + * than or equal to the given [value]. |
| + */ |
| +IMatcher lessThanOrEqualTo(value) => |
|
Bob Nystrom
2012/05/30 23:23:51
Is this really better than doing:
expect(foo > ba
gram
2012/06/01 17:33:15
It gives better error messages. Either can be used
|
| + new _OrderingComparison(value, true, true, false, 'less than or equal to'); |
| + |
| +/** |
| + * Returns a matcher which matches if the match argument is zero. |
| + */ |
| +IMatcher isZero() { |
|
Bob Nystrom
2012/05/30 23:23:51
Make these constants.
gram
2012/06/01 17:33:15
Done.
|
| + return new _OrderingComparison(0, true, false, false, 'equal to'); |
| +} |
| + |
| +/** |
| + * Returns a matcher which matches if the match argument is non-zero. |
| + */ |
| +IMatcher isNonZero() { |
| + return new _OrderingComparison(0, false, true, true, 'not equal to'); |
| +} |
| + |
| +/** |
| + * Returns a matcher which matches if the match argument is positive |
| + * (0 inclusive). |
| + */ |
| +IMatcher isPositive() { |
| + return new _OrderingComparison(0, true, false, true, 'positive', false); |
| +} |
| + |
| +/** |
| + * Returns a matcher which matches if the match argument is negative |
| + * (0 exclusive). |
| + */ |
| +IMatcher isNegative() { |
| + return new _OrderingComparison(0, false, true, false, 'negative', false); |
| +} |
| + |
| +bool _isNumeric(value) { |
| + return value is int || value is double; |
|
Bob Nystrom
2012/05/30 23:23:51
"is num"
But I would just get rid of this. You ca
gram
2012/06/01 17:33:15
This isn't a matcher - it's a utility function use
Bob Nystrom
2012/06/01 18:22:22
Oh, right. Sorry. In either case, you can still si
|
| +} |
| + |
| +class _OrderingComparison extends _NumericMatcher { |
| + |
| + var _value; // Expected value. |
|
Bob Nystrom
2012/05/30 23:23:51
Make these doc comments. Make the fields final.
gram
2012/06/01 17:33:15
Done.
|
| + bool _equalValue; // Return this if values are equal. |
| + bool _lessThanValue; // Return this if test value < expected. |
| + bool _greaterThanValue; // Return this if test value > expected. |
| + String _comparisonDescription; // Textual name of inequality. |
| + bool _valueInDescription; // include value in description? |
| + |
| + _OrderingComparison( |
| + this._value, |
| + bool this._equalValue, |
|
Bob Nystrom
2012/05/30 23:23:51
Remove these type annotations.
gram
2012/06/01 17:33:15
Done.
|
| + bool this._lessThanValue, |
| + bool this._greaterThanValue, |
| + String this._comparisonDescription, |
| + [bool this._valueInDescription = true]) { |
| + if (!_isNumeric(_value)) { |
| + throw new IllegalArgumentException( |
| + 'Expected value for ${_comparisonDescription} must be numeric'); |
| + } |
| + } |
| + |
| + bool matches(item) { |
| + if (!_isNumeric(item)) { |
|
Bob Nystrom
2012/05/30 23:23:51
Should we allow this on user-defined types that im
gram
2012/06/01 17:33:15
Done.
|
| + return false; |
| + } |
| + if (item == _value) { |
| + return _equalValue; |
| + } else if (item < _value) { |
| + return _lessThanValue; |
| + } else { |
| + return _greaterThanValue; |
| + } |
| + } |
| + |
| + IDescription describe(IDescription description) => |
|
Bob Nystrom
2012/05/30 23:23:51
I would use a {} body here.
gram
2012/06/01 17:33:15
Done.
|
| + description.append('a value '). |
| + append(_comparisonDescription). |
| + append(' '). |
| + appendDescriptionOf(_value); |
| +} |
| + |
| +/** |
| + * Returns a matcher which matches if the match argument is within [delta] |
| + * of some [value]; i.e. if the match argument is greater than |
| + * than or equal [value]-[delta] and less than or equal to [value]+[delta]. |
| + */ |
| +IMatcher closeTo(value, delta) => new _IsCloseTo(value, delta); |
| + |
| +class _IsCloseTo extends _NumericMatcher { |
| + |
| + var _value, _delta; |
| + |
| + _IsCloseTo(this._value, this._delta) { |
| + if (!_isNumeric(_value)) { |
| + throw new IllegalArgumentException('IsCloseTo value must be numeric'); |
| + } |
| + if (!_isNumeric(_delta)) { |
| + throw new IllegalArgumentException('IsCloseTo delta must be numeric'); |
| + } |
| + } |
| + |
| + bool matches(item) { |
| + if (!_isNumeric(item)) { |
| + return false; |
| + } |
| + var diff = item - _value; |
| + if (diff < 0) diff = -diff; |
|
Bob Nystrom
2012/05/30 23:23:51
var diff = Math.abs(item - _value);
gram
2012/06/01 17:33:15
There is no Math.abs
Bob Nystrom
2012/06/01 18:22:22
Heh, whoops! Every now and then, the corelib desig
|
| + return (diff <= _delta); |
| + } |
| + |
| + IDescription describeMismatch(item, IDescription mismatchDescription) { |
| + if (_isNumeric(item)) { |
| + var diff = item - _value; |
| + if (diff < 0) diff = -diff; |
| + return mismatchDescription. |
| + appendDescriptionOf(item). |
| + append(' differed by '). |
| + appendDescriptionOf(diff); |
| + } else { |
| + return super.describeMismatch(item, mismatchDescription); |
| + } |
| + } |
| + |
| + IDescription describe(IDescription description) => |
| + description.append('a numeric value within '). |
| + appendDescriptionOf(_delta). |
| + append(' of '). |
| + appendDescriptionOf(_value); |
| +} |
| + |
| +/** |
| + * Returns a matcher which matches if the match argument is greater |
| + * than or equal to a [low] and less than or equal to [high]. |
|
Bob Nystrom
2012/05/30 23:23:51
"to a" -> "to"
gram
2012/06/01 17:33:15
Done.
|
| + */ |
| +IMatcher inInclusiveRange(low, high) => new _InRange(low, high, false, false); |
| + |
| +/** |
| + * Returns a matcher which matches if the match argument is greater |
| + * than [low] and less than [high]. |
| + */ |
| +IMatcher inExclusiveRange(low, high) => new _InRange(low, high, true, true); |
|
Bob Nystrom
2012/05/30 23:23:51
Add a blank line after each member.
gram
2012/06/01 17:33:15
Done.
|
| +/** |
| + * Returns a matcher which matches if the match argument is greater |
| + * than [low] and less than or equal to [high]. |
| + */ |
| +IMatcher inOpenClosedRange(low, high) => new _InRange(low, high, true, false); |
| +/** |
| + * Returns a matcher which matches if the match argument is greater |
| + * than or equal to a [low] and less than [high]. |
| + */ |
| +IMatcher inClosedOpenRange(low, high) => new _InRange(low, high, false, true); |
| + |
| + |
| +class _InRange extends _NumericMatcher { |
| + num _low, _high; |
| + bool _lowExclusive, _highExclusive; |
| + |
| + _InRange(num this._low, num this._high, |
| + bool this._lowExclusive, bool this._highExclusive) { |
| + if (!_isNumeric(_low) || !_isNumeric(_high)) { |
|
Bob Nystrom
2012/05/30 23:23:51
Delete these checks. That's what checked mode is f
gram
2012/06/01 17:33:15
Done.
|
| + throw new |
| + IllegalArgumentException('IsRange range arguments must be numeric'); |
| + } |
| + if (!(_lowExclusive is bool) || !(_highExclusive is bool)) { |
| + throw new IllegalArgumentException('IsRange flag arguments must be bool'); |
| + } |
| + } |
| + |
| + bool matches(value) { |
| + if (!_isNumeric(value)) { |
| + return false; |
| + } |
| + if (value < _low || value > _high) { |
| + return false; |
| + } |
| + if (_lowExclusive && value == _low) { |
| + return false; |
| + } |
| + if (_highExclusive && value == _high) { |
| + return false; |
| + } |
| + return true; |
| + } |
| + |
| + IDescription describe(IDescription description) => |
| + description.append("be in range from " |
| + "$_low (${_lowExclusive?'exclusive':'inclusive'}) to " |
|
Bob Nystrom
2012/05/30 23:23:51
Spaces around ? and :
gram
2012/06/01 17:33:15
Done.
|
| + "$_high (${_highExclusive?'exclusive':'inclusive'})"); |
| + |
| + IDescription describeMismatch(item, IDescription mismatchDescription) { |
| + if (!_isNumeric(item)) { |
| + return mismatchDescription. |
| + appendDescriptionOf(item). |
| + append(' not numeric'); |
| + } else { |
| + return super.describeMismatch(item, mismatchDescription); |
| + } |
| + } |
| +} |
| + |
| + |
| +// Numeric matchers match against a number. We add this intermediate |
| +// class to give better mismatch error messages than the base Matcher class. |
| +class _NumericMatcher extends Matcher { |
| + IDescription describeMismatch(item, IDescription mismatchDescription) { |
| + if (!_isNumeric(item)) { |
| + return mismatchDescription. |
| + appendDescriptionOf(item). |
| + append(' not numeric'); |
| + } else { |
| + return super.describeMismatch(item, mismatchDescription); |
| + } |
| + } |
| +} |