Adds ColorSwatch matcher (#155272)

https://github.com/flutter/flutter/issues/155113

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
gaaclarke 2024-09-17 09:08:22 -07:00 committed by GitHub
parent c4c9f47c47
commit 1db9a61348
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 69 additions and 1 deletions

View File

@ -221,11 +221,27 @@ const Matcher isInCard = _IsInCard();
/// * [isInCard], the opposite.
const Matcher isNotInCard = _IsNotInCard();
/// Default threshold for [isSameColorAs] and [isSameColorSwatchAs].
const double colorEpsilon = 0.004;
/// Asserts that the object represents the same color swatch as [color] when
/// used to paint.
///
/// Specifically this matcher checks the object is of type [ColorSwatch] and its
/// color components fall below the delta specified by [threshold].
///
/// Note: This doesn't recurse into the swatches [Color] type, instead treating
/// them as [Color]s.
Matcher isSameColorSwatchAs<T>(ColorSwatch<T> color,
{double threshold = colorEpsilon}) {
return _ColorSwatchMatcher<T>(color, threshold);
}
/// Asserts that the object represents the same color as [color] when used to paint.
///
/// Specifically this matcher checks the object is of type [Color] and its color
/// components fall below the delta specified by [threshold].
Matcher isSameColorAs(Color color, {double threshold = 0.004}) {
Matcher isSameColorAs(Color color, {double threshold = colorEpsilon}) {
return _ColorMatcher(color, threshold);
}
@ -2138,6 +2154,39 @@ class _CoversSameAreaAs extends Matcher {
description.add('covers expected area and only expected area');
}
class _ColorSwatchMatcher<T> extends Matcher {
_ColorSwatchMatcher(this._target, this._threshold);
final ColorSwatch<T> _target;
final double _threshold;
@override
Description describe(Description description) {
return description.add('matches color swatch "$_target" with threshold "$_threshold".');
}
@override
bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
if (item is ColorSwatch) {
final _ColorMatcher matcher = _ColorMatcher(_target, _threshold);
if (!matcher.matches(item, matchState)) {
return false;
}
for (final T key in _target.keys) {
final _ColorMatcher matcher = _ColorMatcher(_target[key]!, _threshold);
if (!matcher.matches(item[key], matchState)) {
return false;
}
}
return item.keys.length == _target.keys.length;
} else {
return false;
}
}
}
class _ColorMatcher extends Matcher {
_ColorMatcher(this._target, this._threshold);

View File

@ -352,6 +352,25 @@ void main() {
);
});
test('isSameColorSwatchAs', () {
expect(
const ColorSwatch<String>(0xaaaaaaaa,
<String, Color>{'foo': Color(0xaaaaaaaa), 'bar': Color(0xbbbbbbbb)}),
isSameColorSwatchAs(const ColorSwatch<String>(0xaaaaaaaa,
<String, Color>{'foo': Color(0xaaaaaaaa), 'bar': Color(0xbbbbbbbb)})),
);
expect(
const ColorSwatch<String>(0xaaaaaaaa,
<String, Color>{'foo': Color(0xaaaaaaaa), 'bar': Color(0xbbbbbbbb)}),
isNot(isSameColorSwatchAs(const ColorSwatch<String>(
0xaaaaaaaa, <String, Color>{
'foo': Color(0xaaaaaaaa),
'bar': Color(0xcccccccc)
}))),
);
});
test('isSameColorAs', () {
expect(
const Color(0x87654321),