Index: lib/unittest/string_matchers.dart |
=================================================================== |
--- lib/unittest/string_matchers.dart (revision 0) |
+++ lib/unittest/string_matchers.dart (revision 0) |
@@ -0,0 +1,289 @@ |
+// 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 strings that are empty. */ |
+IMatcher isEmptyString() => new _Empty(); |
Bob Nystrom
2012/05/30 23:23:51
Does this add a lot of value over just doing:
exp
|
+ |
+class _Empty extends _StringMatcher { |
+ |
+ _Empty(); |
+ |
+ bool matches(item) => (item is String && item.length == 0); |
+ |
+ IDescription describe(IDescription description) => |
+ description.append('empty string'); |
+} |
+ |
+/** |
+ * Returns a matcher which matches if the interpolated string form of the |
+ * match argument matches the given [matcher]. That is: |
+ * |
+ * expect(foo, isInterpolated(bar)) |
+ * |
+ * is equivalent to: |
+ * |
+ * expect("${foo}", bar) |
+ */ |
+IMatcher isInterpolated(matcher) => new _IsInterpolated(wrapMatcher(matcher)); |
Bob Nystrom
2012/05/30 23:23:51
I think this is equivalent to toString(). Do we ne
gram
2012/06/01 17:33:15
Done.
|
+ |
+class _IsInterpolated extends Matcher { |
+ Matcher _matcher; |
+ |
+ _IsInterpolated(this._matcher) { |
+ if (!(_matcher is Matcher)) { |
+ throw new IllegalArgumentException('isInterpolated expects Matcher'); |
+ } |
+ } |
+ |
+ bool matches(item) => _matcher.matches("${item}"); |
+ |
+ IDescription describe(IDescription description) => |
+ description.appendDescriptionOf(_matcher).append(' interpolated'); |
+} |
+ |
+/** |
+ * Returns a matcher which matches if the match argument is a string and |
+ * is equal to [value] when compared case-insensitively. |
+ */ |
+IMatcher equalToIgnoringCase(String value) => new _IsEqualIgnoringCase(value); |
Bob Nystrom
2012/05/30 23:23:51
"equalTo" -> "equals"
gram
2012/06/01 17:33:15
Done.
|
+ |
+class _IsEqualIgnoringCase extends _StringMatcher { |
+ |
+ String _value; |
+ String _matchValue; |
+ |
+ _IsEqualIgnoringCase(String this._value) { |
+ if (!(_value is String)) { |
Bob Nystrom
2012/05/30 23:23:51
Remove this check.
gram
2012/06/01 17:33:15
Done.
|
+ throw new IllegalArgumentException('equalToIgnoringCase requires string'); |
+ } |
+ _matchValue = _value.toLowerCase(); |
+ } |
+ |
+ bool matches(item) => |
+ (item is String && _matchValue == item.toLowerCase()); |
+ |
+ IDescription describe(IDescription description) => |
+ description.appendDescriptionOf(_value).append(' ignoring case'); |
+} |
+ |
+//--------------------------------------------------------------------- |
+// Utility functions |
Bob Nystrom
2012/05/30 23:23:51
Remove this comment?
gram
2012/06/01 17:33:15
I removed the --- at least.
|
+ |
+bool isWhiteSpace(String ch) => (' \n\r\t'.indexOf(ch) >= 0); |
Bob Nystrom
2012/05/30 23:23:51
There is some debate here, but I think this should
gram
2012/06/01 17:33:15
Done.
|
+ |
+String _stripspace(_string) { |
Bob Nystrom
2012/05/30 23:23:51
"_normalizeWhitespace"?
gram
2012/06/01 17:33:15
Done.
gram
2012/06/01 17:33:15
Done.
|
+ StringBuffer result = new StringBuffer(); |
+ bool skipSpace = true; |
+ for (var i = 0; i < _string.length; i++) { |
+ var character = _string[i]; |
+ if (isWhiteSpace(character)) { |
+ if (!skipSpace) { |
+ result.add(' '); |
+ skipSpace = true; |
+ } |
+ } else { |
+ result.add(character); |
+ skipSpace = false; |
+ } |
+ } |
+ return result.toString().trim(); |
+} |
+ |
+/** |
+ * Returns a matcher which matches if the match argument is a string and |
+ * is equal to [value] when compared with all runs of white space |
Bob Nystrom
2012/05/30 23:23:51
"whitespace"
gram
2012/06/01 17:33:15
Done.
|
+ * collapsed to single spaces and leading and trailing whitespace removed. |
+ * |
+ * For example, equalToIgnoringCase("hello world") will match |
Bob Nystrom
2012/05/30 23:23:51
Put inline code in backticks: `equalToIgnoringWhit
gram
2012/06/01 17:33:15
Done.
|
+ * "hello world", " hello world" and "hello world ". |
+ */ |
+IMatcher equalToIgnoringWhitespace(_string) => |
Bob Nystrom
2012/05/30 23:23:51
"equalTo" -> "equals"
gram
2012/06/01 17:33:15
Done.
|
+ new _IsEqualIgnoringWhiteSpace(_string); |
+ |
+class _IsEqualIgnoringWhiteSpace extends _StringMatcher { |
+ |
+ String _value; |
+ String _matchValue; |
+ |
+ _IsEqualIgnoringWhiteSpace(this._value) { |
+ if (!(_value is String)) { |
Bob Nystrom
2012/05/30 23:23:51
Remove check.
gram
2012/06/01 17:33:15
Done.
|
+ throw new |
+ IllegalArgumentException('equalToIgnoringWhitespace requires string'); |
+ } |
+ _matchValue = _stripspace(_value); |
+ } |
+ |
+ bool matches(item) => (item is String && _matchValue == _stripspace(item)); |
Bob Nystrom
2012/05/30 23:23:51
Unneeded ().
gram
2012/06/01 17:33:15
Done.
|
+ |
+ IDescription describe(IDescription description) => |
+ description.appendDescriptionOf(_matchValue). |
Bob Nystrom
2012/05/30 23:23:51
I would use a {} here. If not, +2 indent.
gram
2012/06/01 17:33:15
Done.
|
+ append(' ignoring whitespace'); |
+ |
+ IDescription describeMismatch(item, IDescription mismatchDescription) { |
+ if (item is String) { |
+ return mismatchDescription.append('was '). |
+ appendDescriptionOf(_stripspace(item)); |
+ } else { |
+ return super.describeMismatch(item, mismatchDescription); |
+ } |
+ } |
+} |
+ |
+/** |
+ * Returns a matcher that matches if the match argument is a string and |
+ * starts with [value]. |
+ */ |
+IMatcher startsWith(substring) => new _StringStartsWith(substring); |
+ |
+class _StringStartsWith extends _StringMatcher { |
+ |
+ String _substring; |
+ |
+ _StringStartsWith(String this._substring) { |
+ if (!(_substring is String)) { |
+ throw new |
+ IllegalArgumentException('startsWith requires a string'); |
+ } |
+ } |
+ |
+ bool matches(item) => (item is String && item.startsWith(_substring)); |
+ |
+ IDescription describe(IDescription description) => |
+ description.append('a string starting with '). |
+ appendDescriptionOf(_substring); |
+} |
+ |
+/** |
+ * Returns a matcher that matches if the match argument is a string and |
+ * ends with [value]. |
+ */ |
+IMatcher endsWith(value) => new _StringEndsWith(value); |
+ |
+class _StringEndsWith extends _StringMatcher { |
+ |
+ String _substring; |
+ |
+ _StringEndsWith(String this._substring) { |
+ if (!(_substring is String)) { |
+ throw new |
+ IllegalArgumentException('endsWith requires a string'); |
Bob Nystrom
2012/05/30 23:23:51
Indent +2.
gram
2012/06/01 17:33:15
Done.
|
+ } |
+ } |
+ |
+ bool matches(item) => (item is String && item.endsWith(_substring)); |
+ |
+ IDescription describe(IDescription description) => |
+ description.append('a string ending with '). |
+ appendDescriptionOf(_substring); |
+} |
+ |
+/** |
+ * Returns a matcher that matches if the match argument is a string and |
+ * contains [substring]. |
+ */ |
+IMatcher containsString(substring) => new _StringContains(substring); |
Bob Nystrom
2012/05/30 23:23:51
Can we do a single unified contains() that works w
gram
2012/06/01 17:33:15
Done.
|
+ |
+class _StringContains extends _StringMatcher { |
+ |
+ String _substring; |
+ |
+ _StringContains(String this._substring) { |
+ if (!(_substring is String)) { |
+ throw new |
+ IllegalArgumentException('containsString requires a string'); |
+ } |
+ } |
+ |
+ bool matches(item) => (item is String && item.indexOf(_substring) >= 0); |
+ |
+ IDescription describe(IDescription description) => |
+ description.append('a string containing '). |
+ appendDescriptionOf(_substring); |
+} |
+ |
+/** |
+ * Returns a matcher that matches if the match argument is a string and |
+ * contains a given list of [substrings] in relative order. |
+ * |
+ * For example, stringContainsInOrder(["a", "e", "i", "o", "u"]) will match |
+ * "abcdefghijklmnopqrstuvwxyz". |
+ */ |
+IMatcher stringContainsInOrder(substrings) => |
+ new _StringContainsInOrder(substrings); |
+ |
+class _StringContainsInOrder extends _StringMatcher { |
+ |
+ List<String> _substrings; |
+ |
+ _StringContainsInOrder(List<String> this._substrings) { |
+ if (!(_substrings is List)) { |
+ throw new IllegalArgumentException( |
+ 'stringContainsInOrder requires a list of strings'); |
+ } |
+ for (var s in _substrings) { |
+ if (!(s is String)) { |
+ throw new IllegalArgumentException( |
+ 'stringContainsInOrder requires a list of strings'); |
+ } |
+ } |
+ } |
+ |
+ bool matches(item) { |
+ if (!(item is String)) { |
+ return false; |
+ } |
+ var from_index = 0; |
+ for (var s in _substrings) { |
+ from_index = item.indexOf(s, from_index); |
+ if (from_index < 0) |
+ return false; |
+ } |
+ return true; |
+ } |
+ |
+ IDescription describe(IDescription description) => |
+ description.appendList('a string containing ', ', ', ' in order', |
+ _substrings); |
+} |
+ |
+/** |
+ * Returns a matcher that matches if the match argument is a string and |
+ * matches the regular expression given by [re]. [re] can be a RegExp |
+ * instance or a string; in the latter case it will be used to create |
+ * a RegExp instance. |
+ */ |
+IMatcher matches(re) => new _MatchesRegExp(re); |
+ |
+class _MatchesRegExp extends _StringMatcher { |
+ RegExp _regexp; |
+ |
+ _MatchesRegExp(re) { |
+ if (re is String) { |
+ _regexp = new RegExp(re); |
+ } else if (re is RegExp) { |
+ _regexp = re; |
+ } else { |
+ throw new IllegalArgumentException('matches requires a regexp or string'); |
+ } |
+ } |
+ |
+ bool matches(String item) => _regexp.hasMatch(item); |
+ |
+ IDescription describe(IDescription description) => |
Bob Nystrom
2012/05/30 23:23:51
Extra space.
gram
2012/06/01 17:33:15
Done.
|
+ description.append("match '${_regexp.pattern}'"); |
+} |
+ |
+// String matchers match against a string. We add this intermediate |
+// class to give better mismatch error messages than the base Matcher class. |
+class _StringMatcher extends Matcher { |
+ IDescription describeMismatch(item, IDescription mismatchDescription) { |
+ if (!(item is String)) { |
+ return mismatchDescription. |
+ appendDescriptionOf(item). |
+ append(' not a string'); |
+ } else { |
+ return super.describeMismatch(item, mismatchDescription); |
+ } |
+ } |
+} |