blob: ab65e5a0312034c90e500c17daed4c8e33b6a695 [file] [log] [blame] [edit]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file is run as part of a reduced test set in CI on Mac and Windows
// machines.
@Tags(<String>['reduced-test-set'])
library;
import 'dart:math' as math;
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
bool _listDoubleMatches(List<double>? x, List<double>? y) {
if (x == null && y == null) {
return true;
}
if (x == null || y == null) {
return false;
}
if (x.length != y.length) {
return false;
}
for (var i = 0; i < x.length; i++) {
if ((x[i] - y[i]).abs() >= 0.0001) {
return false;
}
}
return true;
}
bool _listColorMatches(List<Color> x, List<Color> y) {
if (x.length != y.length) {
return false;
}
const double limit = 1 / 255;
for (var i = 0; i < x.length; i++) {
if ((x[i].a - y[i].a).abs() >= limit ||
(x[i].r - y[i].r).abs() >= limit ||
(x[i].g - y[i].g).abs() >= limit ||
(x[i].b - y[i].b).abs() >= limit) {
return false;
}
}
return true;
}
class _LinearGradientMatcher extends Matcher {
_LinearGradientMatcher(this._target);
final LinearGradient _target;
@override
Description describe(Description description) {
description.add('expected $_target');
return description;
}
@override
bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
return item is LinearGradient &&
item.begin == _target.begin &&
item.end == _target.end &&
item.tileMode == _target.tileMode &&
item.transform == _target.transform &&
_listColorMatches(item.colors, _target.colors) &&
_listDoubleMatches(item.stops, _target.stops);
}
}
Matcher _matchesLinearGradient(LinearGradient target) => _LinearGradientMatcher(target);
class _RadialGradientMatcher extends Matcher {
_RadialGradientMatcher(this._target);
final RadialGradient _target;
@override
Description describe(Description description) {
description.add('expected $_target');
return description;
}
@override
bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
if (item is RadialGradient) {
return item.center == _target.center &&
item.radius == _target.radius &&
item.tileMode == _target.tileMode &&
item.transform == _target.transform &&
item.focal == _target.focal &&
item.focalRadius == _target.focalRadius &&
_listColorMatches(item.colors, _target.colors) &&
_listDoubleMatches(item.stops, _target.stops);
} else {
return false;
}
}
}
Matcher _matchesRadialGradient(RadialGradient target) => _RadialGradientMatcher(target);
class _SweepGradientMatcher extends Matcher {
_SweepGradientMatcher(this._target);
final SweepGradient _target;
@override
Description describe(Description description) {
description.add('expected $_target');
return description;
}
@override
bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
if (item is SweepGradient) {
return item.center == _target.center &&
item.startAngle == _target.startAngle &&
item.endAngle == _target.endAngle &&
item.tileMode == _target.tileMode &&
item.transform == _target.transform &&
_listColorMatches(item.colors, _target.colors) &&
_listDoubleMatches(item.stops, _target.stops);
} else {
return false;
}
}
}
Matcher _matchesSweepGradient(SweepGradient target) => _SweepGradientMatcher(target);
void main() {
test('LinearGradient scale test', () {
const testGradient = LinearGradient(
begin: Alignment.bottomRight,
end: Alignment(0.7, 1.0),
colors: <Color>[Color(0x00FFFFFF), Color(0x11777777), Color(0x44444444)],
);
final LinearGradient? actual = LinearGradient.lerp(null, testGradient, 0.25);
expect(
actual,
_matchesLinearGradient(
const LinearGradient(
begin: Alignment.bottomRight,
end: Alignment(0.7, 1.0),
colors: <Color>[Color(0x00FFFFFF), Color(0x04777777), Color(0x11444444)],
),
),
);
});
test('LinearGradient lerp test', () {
const testGradient1 = LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomLeft,
colors: <Color>[Color(0x33333333), Color(0x66666666)],
);
const testGradient2 = LinearGradient(
begin: Alignment.topRight,
end: Alignment.topLeft,
colors: <Color>[Color(0x44444444), Color(0x88888888)],
);
final LinearGradient? actual = LinearGradient.lerp(testGradient1, testGradient2, 0.5);
expect(
actual,
_matchesLinearGradient(
const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.centerLeft,
colors: <Color>[Color(0x3B3B3B3B), Color(0x77777777)],
stops: <double>[0, 1],
),
),
);
});
test('LinearGradient.lerp identical a,b', () {
expect(LinearGradient.lerp(null, null, 0), null);
const gradient = LinearGradient(colors: <Color>[Color(0x33333333), Color(0x66666666)]);
expect(identical(LinearGradient.lerp(gradient, gradient, 0.5), gradient), true);
});
test('LinearGradient lerp test with stops', () {
const testGradient1 = LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomLeft,
colors: <Color>[Color(0x33333333), Color(0x66666666)],
stops: <double>[0.0, 0.5],
);
const testGradient2 = LinearGradient(
begin: Alignment.topRight,
end: Alignment.topLeft,
colors: <Color>[Color(0x44444444), Color(0x88888888)],
stops: <double>[0.5, 1.0],
);
final LinearGradient? actual = LinearGradient.lerp(testGradient1, testGradient2, 0.5);
expect(
actual,
_matchesLinearGradient(
const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.centerLeft,
colors: <Color>[Color(0x3B3B3B3B), Color(0x55555555), Color(0x77777777)],
stops: <double>[0.0, 0.5, 1.0],
),
),
);
});
test('LinearGradient lerp test with unequal number of colors', () {
const testGradient1 = LinearGradient(colors: <Color>[Color(0x22222222), Color(0x66666666)]);
const testGradient2 = LinearGradient(
colors: <Color>[Color(0x44444444), Color(0x66666666), Color(0x88888888)],
);
final LinearGradient? actual = LinearGradient.lerp(testGradient1, testGradient2, 0.5);
expect(
actual,
_matchesLinearGradient(
const LinearGradient(
colors: <Color>[Color(0x33333333), Color(0x55555555), Color(0x77777777)],
stops: <double>[0.0, 0.5, 1.0],
),
),
);
});
test('LinearGradient lerp test with stops and unequal number of colors', () {
const testGradient1 = LinearGradient(
colors: <Color>[Color(0x33333333), Color(0x66666666)],
stops: <double>[0.0, 0.5],
);
const testGradient2 = LinearGradient(
colors: <Color>[Color(0x44444444), Color(0x48484848), Color(0x88888888)],
stops: <double>[0.5, 0.7, 1.0],
);
final LinearGradient? actual = LinearGradient.lerp(testGradient1, testGradient2, 0.5);
expect(
actual,
_matchesLinearGradient(
const LinearGradient(
colors: <Color>[
Color(0x3B3B3B3B),
Color(0x55555555),
Color(0x57575757),
Color(0x77777777),
],
stops: <double>[0.0, 0.5, 0.7, 1.0],
),
),
);
});
test('LinearGradient lerp test with transforms', () {
const testGradient1 = LinearGradient(
transform: GradientRotation(math.pi / 4),
colors: <Color>[Color(0x33333333), Color(0x66666666)],
stops: <double>[0, 1],
);
const testGradient2 = LinearGradient(
transform: GradientRotation(math.pi / 2),
colors: <Color>[Color(0x33333333), Color(0x66666666)],
stops: <double>[0, 1],
);
final LinearGradient? actual0 = LinearGradient.lerp(testGradient1, testGradient2, 0.0);
final LinearGradient? actual1 = LinearGradient.lerp(testGradient1, testGradient2, 1.0);
final LinearGradient? actual2 = LinearGradient.lerp(testGradient1, testGradient2, 0.5);
expect(testGradient1, equals(actual0));
expect(testGradient2, equals(actual1));
expect(testGradient2, equals(actual2));
});
test('LinearGradient toString', () {
expect(
const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomLeft,
transform: GradientRotation(1.6),
colors: <Color>[Color(0x33333333), Color(0x66666666)],
).toString(),
equals(
'LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomLeft, colors: [${const Color(0x33333333)}, ${const Color(0x66666666)}], tileMode: TileMode.clamp, transform: GradientRotation(radians: 1.6))',
),
);
});
test('LinearGradient with different transforms', () {
const testGradient1 = LinearGradient(
transform: GradientRotation(math.pi / 4),
colors: <Color>[Color(0x33333333), Color(0x66666666)],
);
const testGradient1Copy = LinearGradient(
transform: GradientRotation(math.pi / 4),
colors: <Color>[Color(0x33333333), Color(0x66666666)],
);
const testGradient2 = LinearGradient(
transform: GradientRotation(math.pi / 2),
colors: <Color>[Color(0x33333333), Color(0x66666666)],
);
expect(testGradient1, equals(testGradient1Copy));
expect(testGradient1, isNot(equals(testGradient2)));
});
test('LinearGradient with AlignmentDirectional', () {
expect(() {
return const LinearGradient(
begin: AlignmentDirectional.topStart,
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
}, throwsAssertionError);
expect(() {
return const LinearGradient(
begin: AlignmentDirectional.topStart,
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.rtl);
}, returnsNormally);
expect(() {
return const LinearGradient(
begin: AlignmentDirectional.topStart,
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.ltr);
}, returnsNormally);
expect(() {
return const LinearGradient(
begin: Alignment.topLeft,
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
}, returnsNormally);
});
test('LinearGradient withOpacity test', () {
const testGradient = LinearGradient(
begin: Alignment.bottomRight,
end: Alignment.topCenter,
colors: <Color>[Color(0xFFFFFFFF), Color(0xAF777777), Color(0x44444444)],
);
final LinearGradient actual = testGradient.withOpacity(0.5);
expect(
actual,
const LinearGradient(
begin: Alignment.bottomRight,
end: Alignment.topCenter,
colors: <Color>[Color(0x80FFFFFF), Color(0x80777777), Color(0x80444444)],
),
);
});
test('LinearGradient withOpacity() preserves transform', () {
const testGradient = LinearGradient(
begin: Alignment.bottomRight,
end: Alignment.topCenter,
colors: <Color>[Color(0xFFFFFFFF), Color(0xAF777777), Color(0x44444444)],
transform: GradientRotation(1),
);
final LinearGradient actual = testGradient.withOpacity(0.5);
expect(
actual,
const LinearGradient(
begin: Alignment.bottomRight,
end: Alignment.topCenter,
colors: <Color>[Color(0x80FFFFFF), Color(0x80777777), Color(0x80444444)],
transform: GradientRotation(1),
),
);
});
test('LinearGradient.scale preserves transform', () {
const testGradient = LinearGradient(
begin: Alignment.bottomRight,
end: Alignment.topLeft,
stops: [0, 0.5, 1],
colors: <Color>[Color(0xFFFF0000), Color(0xFF00FF00), Color(0xFF0000FF)],
tileMode: TileMode.decal,
transform: GradientRotation(math.pi / 4),
);
final LinearGradient actual = testGradient.scale(0.5);
expect(
actual,
_matchesLinearGradient(
const LinearGradient(
begin: Alignment.bottomRight,
end: Alignment.topLeft,
stops: [0, 0.5, 1],
colors: <Color>[Color(0x80FF0000), Color(0x8000FF00), Color(0x800000FF)],
tileMode: TileMode.decal,
transform: GradientRotation(math.pi / 4),
),
),
);
});
test('RadialGradient with AlignmentDirectional', () {
expect(() {
return const RadialGradient(
center: AlignmentDirectional.topStart,
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
}, throwsAssertionError);
expect(() {
return const RadialGradient(
center: AlignmentDirectional.topStart,
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.rtl);
}, returnsNormally);
expect(() {
return const RadialGradient(
center: AlignmentDirectional.topStart,
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.ltr);
}, returnsNormally);
expect(() {
return const RadialGradient(
center: Alignment.topLeft,
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
}, returnsNormally);
});
test('RadialGradient lerp test', () {
const testGradient1 = RadialGradient(
center: Alignment.topLeft,
radius: 20.0,
colors: <Color>[Color(0x33333333), Color(0x66666666)],
);
const testGradient2 = RadialGradient(
center: Alignment.topRight,
radius: 10.0,
colors: <Color>[Color(0x44444444), Color(0x88888888)],
);
final RadialGradient? actual = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
expect(
actual,
_matchesRadialGradient(
const RadialGradient(
center: Alignment.topCenter,
radius: 15.0,
colors: <Color>[Color(0x3B3B3B3B), Color(0x77777777)],
stops: <double>[0.0, 1.0],
),
),
);
});
test('RadialGradient.lerp identical a,b', () {
expect(RadialGradient.lerp(null, null, 0), null);
const gradient = RadialGradient(colors: <Color>[Color(0x33333333), Color(0x66666666)]);
expect(identical(RadialGradient.lerp(gradient, gradient, 0.5), gradient), true);
});
test('RadialGradient lerp test with stops', () {
const testGradient1 = RadialGradient(
center: Alignment.topLeft,
radius: 20.0,
colors: <Color>[Color(0x33333333), Color(0x66666666)],
stops: <double>[0.0, 0.5],
);
const testGradient2 = RadialGradient(
center: Alignment.topRight,
radius: 10.0,
colors: <Color>[Color(0x44444444), Color(0x88888888)],
stops: <double>[0.5, 1.0],
);
final RadialGradient? actual = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
expect(
actual,
_matchesRadialGradient(
const RadialGradient(
center: Alignment.topCenter,
radius: 15.0,
colors: <Color>[Color(0x3B3B3B3B), Color(0x55555555), Color(0x77777777)],
stops: <double>[0.0, 0.5, 1.0],
),
),
);
expect(actual!.focal, isNull);
});
test('RadialGradient lerp test with unequal number of colors', () {
const testGradient1 = RadialGradient(colors: <Color>[Color(0x22222222), Color(0x66666666)]);
const testGradient2 = RadialGradient(
colors: <Color>[Color(0x44444444), Color(0x66666666), Color(0x88888888)],
);
final RadialGradient? actual = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
expect(
actual,
_matchesRadialGradient(
const RadialGradient(
colors: <Color>[Color(0x33333333), Color(0x55555555), Color(0x77777777)],
stops: <double>[0.0, 0.5, 1.0],
),
),
);
});
test('RadialGradient lerp test with stops and unequal number of colors', () {
const testGradient1 = RadialGradient(
colors: <Color>[Color(0x33333333), Color(0x66666666)],
stops: <double>[0.0, 0.5],
);
const testGradient2 = RadialGradient(
colors: <Color>[Color(0x44444444), Color(0x48484848), Color(0x88888888)],
stops: <double>[0.5, 0.7, 1.0],
);
final RadialGradient? actual = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
expect(
actual,
_matchesRadialGradient(
const RadialGradient(
colors: <Color>[
Color(0x3B3B3B3B),
Color(0x55555555),
Color(0x57575757),
Color(0x77777777),
],
stops: <double>[0.0, 0.5, 0.7, 1.0],
),
),
);
});
test('RadialGradient lerp test with transforms', () {
const testGradient1 = RadialGradient(
transform: GradientRotation(math.pi / 4),
colors: <Color>[Color(0x33333333), Color(0x66666666)],
stops: <double>[0, 1],
);
const testGradient2 = RadialGradient(
transform: GradientRotation(math.pi / 2),
colors: <Color>[Color(0x33333333), Color(0x66666666)],
stops: <double>[0, 1],
);
final RadialGradient? actual0 = RadialGradient.lerp(testGradient1, testGradient2, 0.0);
final RadialGradient? actual1 = RadialGradient.lerp(testGradient1, testGradient2, 1.0);
final RadialGradient? actual2 = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
expect(testGradient1, equals(actual0));
expect(testGradient2, equals(actual1));
expect(testGradient2, equals(actual2));
});
test('RadialGradient lerp test with focal', () {
const testGradient1 = RadialGradient(
center: Alignment.topLeft,
focal: Alignment.centerLeft,
radius: 20.0,
focalRadius: 10.0,
colors: <Color>[Color(0x33333333), Color(0x66666666)],
);
const testGradient2 = RadialGradient(
center: Alignment.topRight,
focal: Alignment.centerRight,
radius: 10.0,
focalRadius: 5.0,
colors: <Color>[Color(0x44444444), Color(0x88888888)],
);
const testGradient3 = RadialGradient(
center: Alignment.topRight,
radius: 10.0,
colors: <Color>[Color(0x44444444), Color(0x88888888)],
);
final RadialGradient? actual = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
expect(
actual,
_matchesRadialGradient(
const RadialGradient(
center: Alignment.topCenter,
focal: Alignment.center,
radius: 15.0,
focalRadius: 7.5,
colors: <Color>[Color(0x3B3B3B3B), Color(0x77777777)],
stops: <double>[0.0, 1.0],
),
),
);
final RadialGradient? actual2 = RadialGradient.lerp(testGradient1, testGradient3, 0.5);
expect(
actual2,
_matchesRadialGradient(
const RadialGradient(
center: Alignment.topCenter,
focal: Alignment(-0.5, 0.0),
radius: 15.0,
focalRadius: 5.0,
colors: <Color>[Color(0x3B3B3B3B), Color(0x77777777)],
stops: <double>[0.0, 1.0],
),
),
);
});
test('RadialGradient withOpacity test', () {
const testGradient = RadialGradient(
center: Alignment.topLeft,
focal: Alignment.centerLeft,
radius: 20.0,
focalRadius: 10.0,
colors: <Color>[Color(0xFFFFFFFF), Color(0xAF777777), Color(0x44444444)],
);
final RadialGradient actual = testGradient.withOpacity(0.5);
expect(
actual,
const RadialGradient(
center: Alignment.topLeft,
focal: Alignment.centerLeft,
radius: 20.0,
focalRadius: 10.0,
colors: <Color>[Color(0x80FFFFFF), Color(0x80777777), Color(0x80444444)],
),
);
});
test('RadialGradient withOpacity() preserves transform', () {
const testGradient = RadialGradient(
center: Alignment.topLeft,
focal: Alignment.centerLeft,
radius: 20.0,
focalRadius: 10.0,
colors: <Color>[Color(0xFFFFFFFF), Color(0xAF777777), Color(0x44444444)],
transform: GradientRotation(1),
);
final RadialGradient actual = testGradient.withOpacity(0.5);
expect(
actual,
const RadialGradient(
center: Alignment.topLeft,
focal: Alignment.centerLeft,
radius: 20.0,
focalRadius: 10.0,
colors: <Color>[Color(0x80FFFFFF), Color(0x80777777), Color(0x80444444)],
transform: GradientRotation(1),
),
);
});
test('RadialGradient.scale preserves transform', () {
const testGradient = RadialGradient(
center: Alignment.topLeft,
focal: Alignment.centerLeft,
radius: 20.0,
focalRadius: 10.0,
stops: [0, 0.5, 1],
colors: <Color>[Color(0xFFFF0000), Color(0xFF00FF00), Color(0xFF0000FF)],
tileMode: TileMode.decal,
transform: GradientRotation(math.pi / 4),
);
final RadialGradient actual = testGradient.scale(0.5);
expect(
actual,
_matchesRadialGradient(
const RadialGradient(
center: Alignment.topLeft,
focal: Alignment.centerLeft,
radius: 20.0,
focalRadius: 10.0,
stops: [0, 0.5, 1],
colors: <Color>[Color(0x80FF0000), Color(0x8000FF00), Color(0x800000FF)],
tileMode: TileMode.decal,
transform: GradientRotation(math.pi / 4),
),
),
);
});
test('SweepGradient lerp test', () {
const testGradient1 = SweepGradient(
center: Alignment.topLeft,
endAngle: math.pi / 2,
colors: <Color>[Color(0x33333333), Color(0x66666666)],
);
const testGradient2 = SweepGradient(
center: Alignment.topRight,
startAngle: math.pi / 2,
endAngle: math.pi,
colors: <Color>[Color(0x44444444), Color(0x88888888)],
);
final SweepGradient? actual = SweepGradient.lerp(testGradient1, testGradient2, 0.5);
expect(
actual,
_matchesSweepGradient(
const SweepGradient(
center: Alignment.topCenter,
startAngle: math.pi / 4,
endAngle: math.pi * 3 / 4,
colors: <Color>[Color(0x3B3B3B3B), Color(0x77777777)],
stops: <double>[0.0, 1.0],
),
),
);
});
test('SweepGradient.lerp identical a,b', () {
expect(SweepGradient.lerp(null, null, 0), null);
const gradient = SweepGradient(colors: <Color>[Color(0x33333333), Color(0x66666666)]);
expect(identical(SweepGradient.lerp(gradient, gradient, 0.5), gradient), true);
});
test('SweepGradient lerp test with stops', () {
const testGradient1 = SweepGradient(
center: Alignment.topLeft,
endAngle: math.pi / 2,
colors: <Color>[Color(0x33333333), Color(0x66666666)],
stops: <double>[0.0, 0.5],
);
const testGradient2 = SweepGradient(
center: Alignment.topRight,
startAngle: math.pi / 2,
endAngle: math.pi,
colors: <Color>[Color(0x44444444), Color(0x88888888)],
stops: <double>[0.5, 1.0],
);
final SweepGradient? actual = SweepGradient.lerp(testGradient1, testGradient2, 0.5);
expect(
actual,
_matchesSweepGradient(
const SweepGradient(
center: Alignment.topCenter,
startAngle: math.pi / 4,
endAngle: math.pi * 3 / 4,
colors: <Color>[Color(0x3B3B3B3B), Color(0x55555555), Color(0x77777777)],
stops: <double>[0.0, 0.5, 1.0],
),
),
);
});
test('SweepGradient lerp test with unequal number of colors', () {
const testGradient1 = SweepGradient(colors: <Color>[Color(0x22222222), Color(0x66666666)]);
const testGradient2 = SweepGradient(
colors: <Color>[Color(0x44444444), Color(0x66666666), Color(0x88888888)],
);
final SweepGradient? actual = SweepGradient.lerp(testGradient1, testGradient2, 0.5);
expect(
actual,
_matchesSweepGradient(
const SweepGradient(
colors: <Color>[Color(0x33333333), Color(0x55555555), Color(0x77777777)],
stops: <double>[0.0, 0.5, 1.0],
),
),
);
});
test('SweepGradient lerp test with stops and unequal number of colors', () {
const testGradient1 = SweepGradient(
colors: <Color>[Color(0x33333333), Color(0x66666666)],
stops: <double>[0.0, 0.5],
);
const testGradient2 = SweepGradient(
colors: <Color>[Color(0x44444444), Color(0x48484848), Color(0x88888888)],
stops: <double>[0.5, 0.7, 1.0],
);
final SweepGradient? actual = SweepGradient.lerp(testGradient1, testGradient2, 0.5);
expect(
actual,
_matchesSweepGradient(
const SweepGradient(
colors: <Color>[
Color(0x3B3B3B3B),
Color(0x55555555),
Color(0x57575757),
Color(0x77777777),
],
stops: <double>[0.0, 0.5, 0.7, 1.0],
),
),
);
});
test('SweepGradient lerp test with transforms', () {
const testGradient1 = SweepGradient(
transform: GradientRotation(math.pi / 4),
colors: <Color>[Color(0x33333333), Color(0x66666666)],
stops: <double>[0, 1],
);
const testGradient2 = SweepGradient(
transform: GradientRotation(math.pi / 2),
colors: <Color>[Color(0x33333333), Color(0x66666666)],
stops: <double>[0, 1],
);
final SweepGradient? actual0 = SweepGradient.lerp(testGradient1, testGradient2, 0.0);
final SweepGradient? actual1 = SweepGradient.lerp(testGradient1, testGradient2, 1.0);
final SweepGradient? actual2 = SweepGradient.lerp(testGradient1, testGradient2, 0.5);
expect(testGradient1, equals(actual0));
expect(testGradient2, equals(actual1));
expect(testGradient2, equals(actual2));
});
test('SweepGradient scale test)', () {
const testGradient = SweepGradient(
center: Alignment.topLeft,
endAngle: math.pi / 2,
colors: <Color>[Color(0xff333333), Color(0xff666666)],
);
final SweepGradient actual = testGradient.scale(0.5);
expect(
actual,
_matchesSweepGradient(
const SweepGradient(
center: Alignment.topLeft,
endAngle: math.pi / 2,
colors: <Color>[Color(0x80333333), Color(0x80666666)],
),
),
);
});
test('SweepGradient withOpacity test', () {
const testGradient = SweepGradient(
center: Alignment.topLeft,
endAngle: math.pi / 2,
colors: <Color>[Color(0xFFFFFFFF), Color(0xAF777777), Color(0x44444444)],
);
final SweepGradient actual = testGradient.withOpacity(0.5);
expect(
actual,
const SweepGradient(
center: Alignment.topLeft,
endAngle: math.pi / 2,
colors: <Color>[Color(0x80FFFFFF), Color(0x80777777), Color(0x80444444)],
),
);
});
test('SweepGradient withOpacity() preserves transform', () {
const testGradient = SweepGradient(
center: Alignment.topLeft,
endAngle: math.pi / 2,
colors: <Color>[Color(0xFFFFFFFF), Color(0xAF777777), Color(0x44444444)],
transform: GradientRotation(1),
);
final SweepGradient actual = testGradient.withOpacity(0.5);
expect(
actual,
const SweepGradient(
center: Alignment.topLeft,
endAngle: math.pi / 2,
colors: <Color>[Color(0x80FFFFFF), Color(0x80777777), Color(0x80444444)],
transform: GradientRotation(1),
),
);
});
test('SweepGradient.scale preserves transform', () {
const testGradient = SweepGradient(
center: Alignment.topLeft,
startAngle: math.pi / 4,
endAngle: math.pi * 3 / 4,
stops: [0, 0.5, 1],
colors: <Color>[Color(0xFFFF0000), Color(0xFF00FF00), Color(0xFF0000FF)],
tileMode: TileMode.decal,
transform: GradientRotation(math.pi / 4),
);
final SweepGradient actual = testGradient.scale(0.5);
expect(
actual,
_matchesSweepGradient(
const SweepGradient(
center: Alignment.topLeft,
startAngle: math.pi / 4,
endAngle: math.pi * 3 / 4,
stops: [0, 0.5, 1],
colors: <Color>[Color(0x80FF0000), Color(0x8000FF00), Color(0x800000FF)],
tileMode: TileMode.decal,
transform: GradientRotation(math.pi / 4),
),
),
);
});
test('Gradient lerp test (with RadialGradient)', () {
const testGradient1 = RadialGradient(
center: Alignment.topLeft,
radius: 20.0,
colors: <Color>[Color(0x33333333), Color(0x66666666)],
stops: <double>[0.0, 1.0],
);
const testGradient2 = RadialGradient(
center: Alignment.topCenter,
radius: 15.0,
colors: <Color>[Color(0x3B3B3B3B), Color(0x77777777)],
stops: <double>[0.0, 1.0],
);
const testGradient3 = RadialGradient(
center: Alignment.topRight,
radius: 10.0,
colors: <Color>[Color(0x44444444), Color(0x88888888)],
stops: <double>[0.0, 1.0],
);
expect(Gradient.lerp(testGradient1, testGradient3, 0.0), _matchesRadialGradient(testGradient1));
expect(Gradient.lerp(testGradient1, testGradient3, 0.5), _matchesRadialGradient(testGradient2));
expect(Gradient.lerp(testGradient1, testGradient3, 1.0), _matchesRadialGradient(testGradient3));
expect(Gradient.lerp(testGradient3, testGradient1, 0.0), _matchesRadialGradient(testGradient3));
expect(Gradient.lerp(testGradient3, testGradient1, 0.5), _matchesRadialGradient(testGradient2));
expect(Gradient.lerp(testGradient3, testGradient1, 1.0), _matchesRadialGradient(testGradient1));
});
test('Gradient lerp test (LinearGradient to RadialGradient)', () {
const testGradient1 = LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: <Color>[Color(0x33333333), Color(0x66666666)],
);
const testGradient2 = RadialGradient(
radius: 20.0,
colors: <Color>[Color(0x44444444), Color(0x88888888)],
);
expect(Gradient.lerp(testGradient1, testGradient2, 0.0), testGradient1);
expect(Gradient.lerp(testGradient1, testGradient2, 1.0), testGradient2);
expect(Gradient.lerp(testGradient1, testGradient2, 0.5), testGradient2.scale(0.0));
});
test('Gradients can handle missing stops and report mismatched stops', () {
const test1a = LinearGradient(
colors: <Color>[Color(0x11111111), Color(0x22222222), Color(0x33333333)],
);
const test1b = RadialGradient(
colors: <Color>[Color(0x11111111), Color(0x22222222), Color(0x33333333)],
);
const test2a = LinearGradient(
colors: <Color>[Color(0x11111111), Color(0x22222222), Color(0x33333333)],
stops: <double>[0.0, 1.0],
);
const test2b = RadialGradient(
colors: <Color>[Color(0x11111111), Color(0x22222222), Color(0x33333333)],
stops: <double>[0.0, 1.0],
);
const rect = Rect.fromLTWH(1.0, 2.0, 3.0, 4.0);
expect(test1a.createShader(rect), isNotNull);
expect(test1b.createShader(rect), isNotNull);
expect(() {
test2a.createShader(rect);
}, throwsArgumentError);
expect(() {
test2b.createShader(rect);
}, throwsArgumentError);
});
group('Transforms', () {
const colors = <Color>[Color(0xFFFFFFFF), Color(0xFF000088)];
const rect = Rect.fromLTWH(0.0, 0.0, 300.0, 400.0);
const gradients45 = <Gradient>[
LinearGradient(colors: colors, transform: GradientRotation(math.pi / 4)),
// A radial gradient won't be interesting to rotate unless the center is changed.
RadialGradient(
colors: colors,
center: Alignment.topCenter,
transform: GradientRotation(math.pi / 4),
),
SweepGradient(colors: colors, transform: GradientRotation(math.pi / 4)),
];
const gradients90 = <Gradient>[
LinearGradient(colors: colors, transform: GradientRotation(math.pi / 2)),
// A radial gradient won't be interesting to rotate unless the center is changed.
RadialGradient(
colors: colors,
center: Alignment.topCenter,
transform: GradientRotation(math.pi / 2),
),
SweepGradient(colors: colors, transform: GradientRotation(math.pi / 2)),
];
const gradientSnakeCase = <Type, String>{
LinearGradient: 'linear_gradient',
RadialGradient: 'radial_gradient',
SweepGradient: 'sweep_gradient',
};
Future<void> runTest(WidgetTester tester, Gradient gradient, double degrees) async {
final goldenName = '${gradientSnakeCase[gradient.runtimeType]}_$degrees.png';
final Shader shader = gradient.createShader(rect);
final Key painterKey = UniqueKey();
await tester.pumpWidget(
Center(
child: SizedBox.fromSize(
size: rect.size,
child: RepaintBoundary(
key: painterKey,
child: CustomPaint(painter: GradientPainter(shader, rect)),
),
),
),
);
await expectLater(find.byKey(painterKey), matchesGoldenFile(goldenName));
}
group('Gradients - 45 degrees', () {
for (final gradient in gradients45) {
testWidgets('$gradient', (WidgetTester tester) async {
await runTest(tester, gradient, 45);
});
}
});
group('Gradients - 90 degrees', () {
for (final gradient in gradients90) {
testWidgets('$gradient', (WidgetTester tester) async {
await runTest(tester, gradient, 90);
});
}
});
});
}
class GradientPainter extends CustomPainter {
const GradientPainter(this.shader, this.rect);
final Shader shader;
final Rect rect;
@override
void paint(Canvas canvas, Size size) {
canvas.drawRect(rect, Paint()..shader = shader);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}