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); |
+ } |
+ } |
+} |