Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
616794fc
Unverified
Commit
616794fc
authored
Jul 28, 2019
by
Kate Lovett
Committed by
GitHub
Jul 28, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Re-land "Part 1: Skia Gold Testing" (#36103)
parent
24a12894
Changes
39
Hide whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
702 additions
and
265 deletions
+702
-265
.cirrus.yml
.cirrus.yml
+23
-1
download_goldctl.ps1
dev/bots/download_goldctl.ps1
+14
-0
download_goldctl.sh
dev/bots/download_goldctl.sh
+6
-0
date_picker_test.dart
packages/flutter/test/cupertino/date_picker_test.dart
+0
-2
nav_bar_test.dart
packages/flutter/test/cupertino/nav_bar_test.dart
+1
-7
segmented_control_test.dart
packages/flutter/test/cupertino/segmented_control_test.dart
+2
-2
text_field_test.dart
packages/flutter/test/cupertino/text_field_test.dart
+2
-3
bottom_app_bar_test.dart
packages/flutter/test/material/bottom_app_bar_test.dart
+0
-2
bottom_app_bar_theme_test.dart
...ages/flutter/test/material/bottom_app_bar_theme_test.dart
+0
-1
bottom_navigation_bar_test.dart
...ges/flutter/test/material/bottom_navigation_bar_test.dart
+0
-1
card_theme_test.dart
packages/flutter/test/material/card_theme_test.dart
+0
-1
dialog_theme_test.dart
packages/flutter/test/material/dialog_theme_test.dart
+0
-1
dropdown_test.dart
packages/flutter/test/material/dropdown_test.dart
+0
-2
floating_action_button_test.dart
...es/flutter/test/material/floating_action_button_test.dart
+0
-1
input_decorator_test.dart
packages/flutter/test/material/input_decorator_test.dart
+0
-3
material_test.dart
packages/flutter/test/material/material_test.dart
+0
-2
radio_test.dart
packages/flutter/test/material/radio_test.dart
+0
-1
tab_bar_theme_test.dart
packages/flutter/test/material/tab_bar_theme_test.dart
+0
-4
text_field_test.dart
packages/flutter/test/material/text_field_test.dart
+2
-3
continous_rectangle_border_test.dart
...lutter/test/painting/continous_rectangle_border_test.dart
+0
-3
localized_fonts_test.dart
packages/flutter/test/rendering/localized_fonts_test.dart
+0
-3
backdrop_filter_test.dart
packages/flutter/test/widgets/backdrop_filter_test.dart
+0
-1
color_filter_test.dart
packages/flutter/test/widgets/color_filter_test.dart
+0
-2
editable_text_cursor_test.dart
packages/flutter/test/widgets/editable_text_cursor_test.dart
+3
-4
invert_colors_test.dart
packages/flutter/test/widgets/invert_colors_test.dart
+0
-2
list_wheel_scroll_view_test.dart
...ges/flutter/test/widgets/list_wheel_scroll_view_test.dart
+0
-2
opacity_test.dart
packages/flutter/test/widgets/opacity_test.dart
+0
-1
physical_model_test.dart
packages/flutter/test/widgets/physical_model_test.dart
+0
-1
shadow_test.dart
packages/flutter/test/widgets/shadow_test.dart
+4
-6
text_golden_test.dart
packages/flutter/test/widgets/text_golden_test.dart
+20
-26
widget_inspector_test.dart
packages/flutter/test/widgets/widget_inspector_test.dart
+0
-25
flutter_goldens.dart
packages/flutter_goldens/lib/flutter_goldens.dart
+226
-35
flutter_goldens_test.dart
packages/flutter_goldens/test/flutter_goldens_test.dart
+90
-22
client.dart
packages/flutter_goldens_client/lib/client.dart
+39
-22
skia_client.dart
packages/flutter_goldens_client/lib/skia_client.dart
+222
-0
goldens.dart
packages/flutter_test/lib/src/goldens.dart
+26
-1
matchers.dart
packages/flutter_test/lib/src/matchers.dart
+4
-14
goldens_test.dart
packages/flutter_test/test/goldens_test.dart
+13
-0
matchers_test.dart
packages/flutter_test/test/matchers_test.dart
+5
-58
No files found.
.cirrus.yml
View file @
616794fc
...
...
@@ -63,6 +63,9 @@ task:
GCLOUD_SERVICE_ACCOUNT_KEY
:
ENCRYPTED[f12abe60f5045d619ef4c79b83dd1e0722a0b0b13dbea95fbe334e2db7fffbcd841a5a92da8824848b539a19afe0c9fb]
SHARD
:
tests
SUBSHARD
:
widgets
GOLDCTL
:
"
$CIRRUS_WORKING_DIR/depot_tools/goldctl"
GOLD_SERVICE_ACCOUNT
:
ENCRYPTED[3afeea5ac7201151c3d0dc9648862f0462b5e4f55dc600ca8b692319622f7c3eda3d577b1b16cc2ef0311b7314c1c095]
goldctl_script
:
./dev/bots/download_goldctl.sh
test_script
:
-
dart --enable-asserts ./dev/bots/test.dart
container
:
...
...
@@ -73,6 +76,9 @@ task:
GCLOUD_SERVICE_ACCOUNT_KEY
:
ENCRYPTED[f12abe60f5045d619ef4c79b83dd1e0722a0b0b13dbea95fbe334e2db7fffbcd841a5a92da8824848b539a19afe0c9fb]
SHARD
:
tests
SUBSHARD
:
framework_other
GOLDCTL
:
"
$CIRRUS_WORKING_DIR/depot_tools/goldctl"
GOLD_SERVICE_ACCOUNT
:
ENCRYPTED[3afeea5ac7201151c3d0dc9648862f0462b5e4f55dc600ca8b692319622f7c3eda3d577b1b16cc2ef0311b7314c1c095]
goldctl_script
:
./dev/bots/download_goldctl.sh
test_script
:
-
dart --enable-asserts ./dev/bots/test.dart
container
:
...
...
@@ -310,6 +316,9 @@ task:
GCLOUD_SERVICE_ACCOUNT_KEY
:
ENCRYPTED[f12abe60f5045d619ef4c79b83dd1e0722a0b0b13dbea95fbe334e2db7fffbcd841a5a92da8824848b539a19afe0c9fb]
SHARD
:
tests
SUBSHARD
:
widgets
GOLDCTL
:
"
C:
\\
Windows
\\
Temp
\\
depot_tools
\\
goldctl.exe"
GOLD_SERVICE_ACCOUNT
:
ENCRYPTED[3afeea5ac7201151c3d0dc9648862f0462b5e4f55dc600ca8b692319622f7c3eda3d577b1b16cc2ef0311b7314c1c095]
goldctl_script
:
powershell dev\bots\download_goldctl.ps1
test_all_script
:
-
dart --enable-asserts dev\bots\test.dart
-
name
:
tests_framework_other-windows
...
...
@@ -317,6 +326,9 @@ task:
GCLOUD_SERVICE_ACCOUNT_KEY
:
ENCRYPTED[f12abe60f5045d619ef4c79b83dd1e0722a0b0b13dbea95fbe334e2db7fffbcd841a5a92da8824848b539a19afe0c9fb]
SHARD
:
tests
SUBSHARD
:
framework_other
GOLDCTL
:
"
C:
\\
Windows
\\
Temp
\\
depot_tools
\\
goldctl.exe"
GOLD_SERVICE_ACCOUNT
:
ENCRYPTED[3afeea5ac7201151c3d0dc9648862f0462b5e4f55dc600ca8b692319622f7c3eda3d577b1b16cc2ef0311b7314c1c095]
goldctl_script
:
powershell dev\bots\download_goldctl.ps1
test_all_script
:
-
dart --enable-asserts dev\bots\test.dart
-
name
:
tests_extras-windows
...
...
@@ -441,7 +453,7 @@ task:
task
:
use_compute_credits
:
$CIRRUS_USER_COLLABORATOR == 'true'
osx_instance
:
image
:
mojave-xcode-10.
1
image
:
mojave-xcode-10.
2
depends_on
:
-
analyze
env
:
...
...
@@ -477,17 +489,27 @@ task:
GCLOUD_SERVICE_ACCOUNT_KEY
:
ENCRYPTED[f12abe60f5045d619ef4c79b83dd1e0722a0b0b13dbea95fbe334e2db7fffbcd841a5a92da8824848b539a19afe0c9fb]
SHARD
:
tests
SUBSHARD
:
widgets
GOLDCTL
:
"
$CIRRUS_WORKING_DIR/depot_tools/goldctl"
GOLD_SERVICE_ACCOUNT
:
ENCRYPTED[3afeea5ac7201151c3d0dc9648862f0462b5e4f55dc600ca8b692319622f7c3eda3d577b1b16cc2ef0311b7314c1c095]
goldctl_script
:
./dev/bots/download_goldctl.sh
test_all_script
:
-
ulimit -S -n 2048
# https://github.com/flutter/flutter/issues/2976
-
dart --enable-asserts dev/bots/test.dart
on_failure
:
print_failure_time_script
:
date
-
name
:
tests_framework_other-macos
env
:
GCLOUD_SERVICE_ACCOUNT_KEY
:
ENCRYPTED[f12abe60f5045d619ef4c79b83dd1e0722a0b0b13dbea95fbe334e2db7fffbcd841a5a92da8824848b539a19afe0c9fb]
SHARD
:
tests
SUBSHARD
:
framework_other
GOLDCTL
:
"
$CIRRUS_WORKING_DIR/depot_tools/goldctl"
GOLD_SERVICE_ACCOUNT
:
ENCRYPTED[3afeea5ac7201151c3d0dc9648862f0462b5e4f55dc600ca8b692319622f7c3eda3d577b1b16cc2ef0311b7314c1c095]
goldctl_script
:
./dev/bots/download_goldctl.sh
test_all_script
:
-
ulimit -S -n 2048
# https://github.com/flutter/flutter/issues/2976
-
dart --enable-asserts dev/bots/test.dart
on_failure
:
print_failure_time_script
:
date
-
name
:
tests_extras-macos
env
:
GCLOUD_SERVICE_ACCOUNT_KEY
:
ENCRYPTED[f12abe60f5045d619ef4c79b83dd1e0722a0b0b13dbea95fbe334e2db7fffbcd841a5a92da8824848b539a19afe0c9fb]
...
...
dev/bots/download_goldctl.ps1
0 → 100644
View file @
616794fc
$url
=
"https://storage.googleapis.com/chrome-infra/depot_tools.zip"
$zipPath
=
"C:\Windows\Temp\depot_tools.zip"
$path
=
"C:\Windows\Temp\depot_tools"
$gclient
=
"C:\Windows\Temp\depot_tools\gclient.bat"
$cipd
=
"C:\Windows\Temp\depot_tools\cipd.bat"
$ensureFile
=
"C:\Windows\Temp\depot_tools\ensure.txt"
$text
=
"# Ensure File
`n`$
ServiceURL https://chrome-infra-packages.appspot.com
`n`n
# Skia Gold Client goldctl
`n
skia/tools/goldctl/
`$
{platform} latest"
(
New-Object
System.Net.WebClient
)
.DownloadFile
(
$url
,
$zipPath
)
Expand-Archive
-LiteralPath
$zipPath
-DestinationPath
$path
cd
$path
cmd.exe /C
"
$gclient
"
$text
|
Out-File
-filePath
$ensureFile
-encoding ascii
cmd.exe /C
"
$cipd
ensure -ensure-file
$ensureFile
-root
$path
"
dev/bots/download_goldctl.sh
0 → 100755
View file @
616794fc
#!/usr/bin/env bash
git clone
--depth
1 https://chromium.googlesource.com/chromium/tools/depot_tools.git ./depot_tools
cd
depot_tools
echo
-e
'# Ensure File\n$ServiceURL https://chrome-infra-packages.appspot.com\n\n# Skia Gold Client goldctl\nskia/tools/goldctl/${platform} latest'
>
ensure.txt
./cipd ensure
-ensure-file
./ensure.txt
-root
.
packages/flutter/test/cupertino/date_picker_test.dart
View file @
616794fc
...
...
@@ -847,7 +847,6 @@ void main() {
'date_picker_test.datetime.initial.png'
,
version:
1
,
),
skip:
!
isLinux
);
// Slightly drag the hour component to make the current hour off-center.
...
...
@@ -860,7 +859,6 @@ void main() {
'date_picker_test.datetime.drag.png'
,
version:
1
,
),
skip:
!
isLinux
);
});
});
...
...
packages/flutter/test/cupertino/nav_bar_test.dart
View file @
616794fc
...
...
@@ -805,9 +805,6 @@ void main() {
),
);
},
// TODO(xster): remove once https://github.com/flutter/flutter/issues/17483
// is fixed.
skip:
!
isLinux
,
);
testWidgets
(
...
...
@@ -842,10 +839,7 @@ void main() {
),
);
},
// TODO(xster): remove once https://github.com/flutter/flutter/issues/17483
// is fixed.
skip:
!
isLinux
,
);
);
testWidgets
(
'NavBar draws a light system bar for a dark background'
,
(
WidgetTester
tester
)
async
{
...
...
packages/flutter/test/cupertino/segmented_control_test.dart
View file @
616794fc
...
...
@@ -1417,7 +1417,7 @@ void main() {
version:
0
,
),
);
}
,
skip:
!
isLinux
);
});
testWidgets
(
'Golden Test Pressed State'
,
(
WidgetTester
tester
)
async
{
final
Map
<
int
,
Widget
>
children
=
<
int
,
Widget
>{};
...
...
@@ -1458,5 +1458,5 @@ void main() {
version:
0
,
),
);
}
,
skip:
!
isLinux
);
});
}
packages/flutter/test/cupertino/text_field_test.dart
View file @
616794fc
...
...
@@ -481,7 +481,7 @@ void main() {
version:
2
,
),
);
}
,
skip:
!
isLinux
);
});
testWidgets
(
'Cupertino cursor iOS golden'
,
(
WidgetTester
tester
)
async
{
debugDefaultTargetPlatformOverride
=
TargetPlatform
.
iOS
;
...
...
@@ -514,7 +514,7 @@ void main() {
version:
2
,
),
);
}
,
skip:
!
isLinux
);
});
testWidgets
(
'can control text content via controller'
,
...
...
@@ -2901,7 +2901,6 @@ void main() {
'text_field_test.disabled.png'
,
version:
0
,
),
skip:
!
isLinux
,
);
});
...
...
packages/flutter/test/material/bottom_app_bar_test.dart
View file @
616794fc
...
...
@@ -75,7 +75,6 @@ void main() {
'bottom_app_bar.custom_shape.1.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
await
pump
(
FloatingActionButtonLocation
.
centerDocked
);
await
tester
.
pumpAndSettle
();
...
...
@@ -85,7 +84,6 @@ void main() {
'bottom_app_bar.custom_shape.2.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
packages/flutter/test/material/bottom_app_bar_theme_test.dart
View file @
616794fc
...
...
@@ -84,7 +84,6 @@ void main() {
'bottom_app_bar_theme.custom_shape.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
packages/flutter/test/material/bottom_navigation_bar_test.dart
View file @
616794fc
...
...
@@ -1438,7 +1438,6 @@ void main() {
'bottom_navigation_bar.shifting_transition.
$pump
.png'
,
version:
2
,
),
skip:
!
isLinux
,
);
}
},
skip:
isBrowser
);
...
...
packages/flutter/test/material/card_theme_test.dart
View file @
616794fc
...
...
@@ -141,7 +141,6 @@ void main() {
'card_theme.custom_shape.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
}
...
...
packages/flutter/test/material/dialog_theme_test.dart
View file @
616794fc
...
...
@@ -134,7 +134,6 @@ void main() {
'dialog_theme.dialog_with_custom_border.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
packages/flutter/test/material/dropdown_test.dart
View file @
616794fc
...
...
@@ -144,7 +144,6 @@ void main() {
'dropdown_test.default.png'
,
version:
0
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
@@ -160,7 +159,6 @@ void main() {
'dropdown_test.expanded.png'
,
version:
0
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
packages/flutter/test/material/floating_action_button_test.dart
View file @
616794fc
...
...
@@ -740,7 +740,6 @@ void main() {
'floating_action_button_test.clip.png'
,
version:
2
,
),
skip:
!
isLinux
,
);
});
...
...
packages/flutter/test/material/input_decorator_test.dart
View file @
616794fc
...
...
@@ -2865,7 +2865,6 @@ void main() {
'input_decorator.outline_icon_label.ltr.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
await
tester
.
pumpWidget
(
buildFrame
(
TextDirection
.
rtl
));
...
...
@@ -2875,10 +2874,8 @@ void main() {
'input_decorator.outline_icon_label.rtl.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
!
isLinux
,
);
testWidgets
(
'InputDecorator draws and animates hoverColor'
,
(
WidgetTester
tester
)
async
{
...
...
packages/flutter/test/material/material_test.dart
View file @
616794fc
...
...
@@ -698,7 +698,6 @@ void main() {
'material.border_paint_above.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
@@ -742,7 +741,6 @@ void main() {
'material.border_paint_below.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
});
...
...
packages/flutter/test/material/radio_test.dart
View file @
616794fc
...
...
@@ -280,7 +280,6 @@ void main() {
'radio.ink_ripple.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
}
...
...
packages/flutter/test/material/tab_bar_theme_test.dart
View file @
616794fc
...
...
@@ -271,7 +271,6 @@ void main() {
'tab_bar_theme.tab_indicator_size_tab.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
@@ -286,7 +285,6 @@ void main() {
'tab_bar_theme.tab_indicator_size_label.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
@@ -306,7 +304,6 @@ void main() {
'tab_bar_theme.custom_tab_indicator.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
@@ -326,7 +323,6 @@ void main() {
'tab_bar_theme.beveled_rect_indicator.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
}
packages/flutter/test/material/text_field_test.dart
View file @
616794fc
...
...
@@ -416,7 +416,7 @@ void main() {
version:
0
,
),
);
}
,
skip:
!
isLinux
);
});
testWidgets
(
'Material cursor iOS golden'
,
(
WidgetTester
tester
)
async
{
debugDefaultTargetPlatformOverride
=
TargetPlatform
.
iOS
;
...
...
@@ -448,7 +448,7 @@ void main() {
version:
0
,
),
);
}
,
skip:
!
isLinux
);
});
testWidgets
(
'text field selection toolbar renders correctly inside opacity'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -501,7 +501,6 @@ void main() {
'text_field_opacity_test.0.png'
,
version:
2
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
packages/flutter/test/painting/continous_rectangle_border_test.dart
View file @
616794fc
...
...
@@ -75,7 +75,6 @@ void main() {
'continuous_rectangle_border.golden_test_even_radii.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
@@ -100,7 +99,6 @@ void main() {
'continuous_rectangle_border.golden_test_varying_radii.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
@@ -122,7 +120,6 @@ void main() {
'continuous_rectangle_border.golden_test_large_radii.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
packages/flutter/test/rendering/localized_fonts_test.dart
View file @
616794fc
...
...
@@ -55,7 +55,6 @@ void main() {
),
);
},
skip:
!
isLinux
,
);
testWidgets
(
...
...
@@ -110,7 +109,6 @@ void main() {
),
);
},
skip:
!
isLinux
,
);
testWidgets
(
...
...
@@ -157,7 +155,6 @@ void main() {
),
);
},
skip:
!
isLinux
,
);
}
packages/flutter/test/widgets/backdrop_filter_test.dart
View file @
616794fc
...
...
@@ -47,7 +47,6 @@ void main() {
'backdrop_filter_test.cull_rect.png'
,
version:
1
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
}
packages/flutter/test/widgets/color_filter_test.dart
View file @
616794fc
...
...
@@ -21,7 +21,6 @@ void main() {
'color_filter_red.png'
,
version:
1
,
),
skip:
!
isLinux
);
});
...
...
@@ -63,7 +62,6 @@ void main() {
'color_filter_sepia.png'
,
version:
1
,
),
skip:
!
isLinux
);
});
}
\ No newline at end of file
packages/flutter/test/widgets/editable_text_cursor_test.dart
View file @
616794fc
...
...
@@ -95,7 +95,7 @@ void main() {
version:
3
,
),
);
}
,
skip:
!
isLinux
);
});
testWidgets
(
'cursor layout has correct radius'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
<
EditableTextState
>
editableTextKey
=
GlobalKey
<
EditableTextState
>();
...
...
@@ -149,7 +149,7 @@ void main() {
version:
3
,
),
);
}
,
skip:
!
isLinux
);
});
testWidgets
(
'Cursor animates on iOS'
,
(
WidgetTester
tester
)
async
{
final
Widget
widget
=
MaterialApp
(
...
...
@@ -803,6 +803,5 @@ void main() {
),
);
debugDefaultTargetPlatformOverride
=
null
;
},
skip:
!
isLinux
);
});
}
packages/flutter/test/widgets/invert_colors_test.dart
View file @
616794fc
...
...
@@ -24,7 +24,6 @@ void main() {
'invert_colors_test.0.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
@@ -46,7 +45,6 @@ void main() {
'invert_colors_test.1.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
}
...
...
packages/flutter/test/widgets/list_wheel_scroll_view_test.dart
View file @
616794fc
...
...
@@ -539,7 +539,6 @@ void main() {
'list_wheel_scroll_view.center_child.magnified.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
@@ -597,7 +596,6 @@ void main() {
'list_wheel_scroll_view.curved_wheel.left.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
packages/flutter/test/widgets/opacity_test.dart
View file @
616794fc
...
...
@@ -181,7 +181,6 @@ void main() {
'opacity_test.offset.png'
,
version:
1
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
packages/flutter/test/widgets/physical_model_test.dart
View file @
616794fc
...
...
@@ -114,7 +114,6 @@ void main() {
'physical_model_overflow.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
packages/flutter/test/widgets/shadow_test.dart
View file @
616794fc
...
...
@@ -37,8 +37,7 @@ void main() {
'shadow.BoxDecoration.enabled.png'
,
version:
null
,
),
skip:
!
isLinux
);
// shadows render differently on different platforms
);
debugDisableShadows
=
true
;
},
skip:
isBrowser
);
...
...
@@ -70,7 +69,7 @@ void main() {
);
}
debugDisableShadows
=
true
;
}
,
skip:
!
isLinux
);
// shadows render differently on different platforms
}
);
testWidgets
(
'Shadows with PhysicalLayer'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -107,8 +106,7 @@ void main() {
'shadow.PhysicalModel.enabled.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
// shadows render differently on different platforms
);
debugDisableShadows
=
true
;
},
skip:
isBrowser
);
...
...
@@ -144,5 +142,5 @@ void main() {
);
}
debugDisableShadows
=
true
;
}
,
skip:
!
isLinux
);
// shadows render differently on different platforms
}
);
}
packages/flutter/test/widgets/text_golden_test.dart
View file @
616794fc
...
...
@@ -62,7 +62,7 @@ void main() {
version:
null
,
),
);
}
,
skip:
!
isLinux
);
});
testWidgets
(
'Text Foreground'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -147,7 +147,7 @@ void main() {
version:
null
,
),
);
}
,
skip:
!
isLinux
);
});
// TODO(garyq): This test requires an update when the background
// drawing from the beginning of the line bug is fixed. The current
...
...
@@ -200,7 +200,7 @@ void main() {
version:
null
,
),
);
}
,
skip:
!
isLinux
);
});
testWidgets
(
'Text Fade'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -239,7 +239,7 @@ void main() {
version:
1
,
),
);
}
,
skip:
!
isLinux
);
});
testWidgets
(
'Default Strut text'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -267,8 +267,7 @@ void main() {
version:
null
,
),
);
},
skip:
true
);
// Should only be on linux (skip: !isLinux).
// Disabled for now until font inconsistency is resolved.
});
testWidgets
(
'Strut text 1'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -298,8 +297,7 @@ void main() {
version:
1
,
),
);
},
skip:
true
);
// Should only be on linux (skip: !isLinux).
// Disabled for now until font inconsistency is resolved.
});
testWidgets
(
'Strut text 2'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -330,8 +328,7 @@ void main() {
version:
1
,
),
);
},
skip:
true
);
// Should only be on linux (skip: !isLinux).
// Disabled for now until font inconsistency is resolved.
});
testWidgets
(
'Strut text rich'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -385,8 +382,7 @@ void main() {
version:
1
,
),
);
},
skip:
true
);
// Should only be on linux (skip: !isLinux).
// Disabled for now until font inconsistency is resolved.
});
testWidgets
(
'Strut text font fallback'
,
(
WidgetTester
tester
)
async
{
// Font Fallback
...
...
@@ -424,8 +420,7 @@ void main() {
version:
1
,
),
);
},
skip:
true
);
// Should only be on linux (skip: !isLinux).
// Disabled for now until font inconsistency is resolved.
});
testWidgets
(
'Strut text rich forceStrutHeight'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -479,8 +474,7 @@ void main() {
version:
1
,
),
);
},
skip:
true
);
// Should only be on linux (skip: !isLinux).
// Disabled for now until font inconsistency is resolved.
});
testWidgets
(
'Decoration thickness'
,
(
WidgetTester
tester
)
async
{
final
TextDecoration
allDecorations
=
TextDecoration
.
combine
(
...
...
@@ -521,7 +515,7 @@ void main() {
version:
0
,
),
);
}
,
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
}
);
testWidgets
(
'Decoration thickness'
,
(
WidgetTester
tester
)
async
{
final
TextDecoration
allDecorations
=
TextDecoration
.
combine
(
...
...
@@ -563,7 +557,7 @@ void main() {
version:
1
,
),
);
}
,
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
}
);
testWidgets
(
'Text Inline widget'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -660,7 +654,7 @@ void main() {
version:
1
,
),
);
}
,
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
}
);
testWidgets
(
'Text Inline widget textfield'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -708,7 +702,7 @@ void main() {
version:
2
,
),
);
}
,
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
}
);
// This tests if multiple Text.rich widgets are able to inline nest within each other.
testWidgets
(
'Text Inline widget nesting'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -840,7 +834,7 @@ void main() {
version:
2
,
),
);
}
,
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
}
);
testWidgets
(
'Text Inline widget baseline'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -950,7 +944,7 @@ void main() {
version:
1
,
),
);
}
,
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
}
);
testWidgets
(
'Text Inline widget aboveBaseline'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -1060,7 +1054,7 @@ void main() {
version:
1
,
),
);
}
,
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
}
);
testWidgets
(
'Text Inline widget belowBaseline'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -1170,7 +1164,7 @@ void main() {
version:
1
,
),
);
}
,
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
}
);
testWidgets
(
'Text Inline widget top'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -1280,7 +1274,7 @@ void main() {
version:
1
,
),
);
}
,
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
}
);
testWidgets
(
'Text Inline widget middle'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
...
...
@@ -1390,5 +1384,5 @@ void main() {
version:
1
,
),
);
}
,
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
}
);
}
packages/flutter/test/widgets/widget_inspector_test.dart
View file @
616794fc
...
...
@@ -2028,7 +2028,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.repaint_boundary_margin.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
// Regression test for how rendering with a pixel scale other than 1.0
...
...
@@ -2042,7 +2041,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.repaint_boundary_margin_small.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
await
expectLater
(
...
...
@@ -2054,7 +2052,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.repaint_boundary_margin_large.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
final
Layer
layerParent
=
layer
.
parent
;
...
...
@@ -2073,7 +2070,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.repaint_boundary.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
// Verify that taking a screenshot didn't change the layers associated with
...
...
@@ -2094,7 +2090,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.repaint_boundary_margin.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
// Verify that taking a screenshot didn't change the layers associated with
...
...
@@ -2118,7 +2113,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.repaint_boundary_debugPaint.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
// Verify that taking a screenshot with debug paint on did not change
// the number of children the layer has.
...
...
@@ -2132,7 +2126,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.repaint_boundary.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
expect
(
renderObject
.
debugLayer
,
equals
(
layer
));
...
...
@@ -2149,7 +2142,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.container.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
await
expectLater
(
...
...
@@ -2163,7 +2155,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.container_debugPaint.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
{
...
...
@@ -2187,7 +2178,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.container_debugPaint.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
expect
(
container
.
debugNeedsLayout
,
isFalse
);
}
...
...
@@ -2203,7 +2193,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.container_small.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
await
expectLater
(
...
...
@@ -2217,7 +2206,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.container_large.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
// This screenshot will show the clip rect debug paint but no other
...
...
@@ -2233,7 +2221,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.clipRect_debugPaint.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
final
Element
clipRect
=
find
.
byType
(
ClipRRect
).
evaluate
().
single
;
...
...
@@ -2253,7 +2240,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.clipRect_debugPaint_margin.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
// Verify we get the same image if we go through the service extension
...
...
@@ -2296,7 +2282,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.padding_debugPaint.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
// The bounds for this box crop its rendered content.
...
...
@@ -2311,7 +2296,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.sizedBox_debugPaint.png'
,
version:
1
,
),
skip:
!
isLinux
,
);
// Verify that setting a margin includes the previously cropped content.
...
...
@@ -2327,7 +2311,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.sizedBox_debugPaint_margin.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
@@ -2467,7 +2450,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.composited_transform.only_offsets.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
await
expectLater
(
...
...
@@ -2480,7 +2462,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.composited_transform.only_offsets_follower.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
await
expectLater
(
...
...
@@ -2489,7 +2470,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.composited_transform.only_offsets_small.png'
,
version:
1
,
),
skip:
!
isLinux
,
);
await
expectLater
(
...
...
@@ -2502,7 +2482,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.composited_transform.only_offsets_target.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
},
skip:
isBrowser
);
...
...
@@ -2578,7 +2557,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.composited_transform.with_rotations.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
await
expectLater
(
...
...
@@ -2591,7 +2569,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.composited_transform.with_rotations_small.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
await
expectLater
(
...
...
@@ -2604,7 +2581,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.composited_transform.with_rotations_target.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
await
expectLater
(
...
...
@@ -2617,7 +2593,6 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
'inspector.composited_transform.with_rotations_follower.png'
,
version:
null
,
),
skip:
!
isLinux
,
);
// Make sure taking screenshots hasn't modified the positions of the
...
...
packages/flutter_goldens/lib/flutter_goldens.dart
View file @
616794fc
...
...
@@ -9,79 +9,150 @@ import 'package:file/file.dart';
import
'package:file/local.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:meta/meta.dart'
;
import
'package:platform/platform.dart'
;
import
'package:flutter_goldens_client/client.dart'
;
import
'package:flutter_goldens_client/skia_client.dart'
;
export
'package:flutter_goldens_client/client.dart'
;
export
'package:flutter_goldens_client/skia_client.dart'
;
/// Main method that can be used in a `flutter_test_config.dart` file to set
/// [goldenFileComparator] to an instance of [FlutterGoldenFileComparator] that
/// works for the current test.
/// works for the current test. _Which_ FlutterGoldenFileComparator is
/// instantiated is based on the current testing environment.
Future
<
void
>
main
(
FutureOr
<
void
>
testMain
())
async
{
goldenFileComparator
=
await
FlutterGoldenFileComparator
.
fromDefaultComparator
();
const
Platform
platform
=
LocalPlatform
();
if
(
FlutterSkiaGoldFileComparator
.
isAvailableOnPlatform
(
platform
))
{
goldenFileComparator
=
await
FlutterSkiaGoldFileComparator
.
fromDefaultComparator
();
}
else
if
(
FlutterGoldensRepositoryFileComparator
.
isAvailableOnPlatform
(
platform
))
{
goldenFileComparator
=
await
FlutterGoldensRepositoryFileComparator
.
fromDefaultComparator
();
}
else
{
goldenFileComparator
=
FlutterSkippingGoldenFileComparator
.
fromDefaultComparator
();
}
await
testMain
();
}
/// A golden file comparator specific to the `flutter/flutter` repository.
///
/// Within the https://github.com/flutter/flutter repository, it's important
/// not to check-in binaries in order to keep the size of the repository to a
/// minimum. To satisfy this requirement, this comparator retrieves the golden
/// files from a sibling repository, `flutter/goldens`.
///
/// This comparator will locally clone the `flutter/goldens` repository into
/// the `$FLUTTER_ROOT/bin/cache/pkg/goldens` folder, then perform the comparison against
/// the files therein.
class
FlutterGoldenFileComparator
implements
GoldenFileComparator
{
/// Abstract base class golden file comparator specific to the `flutter/flutter`
/// repository.
abstract
class
FlutterGoldenFileComparator
extends
GoldenFileComparator
{
/// Creates a [FlutterGoldenFileComparator] that will resolve golden file
/// URIs relative to the specified [basedir].
///
/// The [fs] parameter exists for testing purposes only.
/// The [fs] and [platform] parameters useful in tests, where the default file
/// system and platform can be replaced by mock instances.
@visibleForTesting
FlutterGoldenFileComparator
(
this
.
basedir
,
{
this
.
fs
=
const
LocalFileSystem
(),
});
this
.
platform
=
const
LocalPlatform
(),
})
:
assert
(
basedir
!=
null
),
assert
(
fs
!=
null
),
assert
(
platform
!=
null
);
/// The directory to which golden file URIs will be resolved in [compare] and [update].
/// The directory to which golden file URIs will be resolved in [compare] and
/// [update].
final
Uri
basedir
;
/// The file system used to perform file access.
@visibleForTesting
final
FileSystem
fs
;
/// Creates a new [FlutterGoldenFileComparator] that mirrors the relative
/// path resolution of the default [goldenFileComparator].
/// A wrapper for the [dart:io.Platform] API.
@visibleForTesting
final
Platform
platform
;
@override
Future
<
void
>
update
(
Uri
golden
,
Uint8List
imageBytes
)
async
{
final
File
goldenFile
=
getGoldenFile
(
golden
);
await
goldenFile
.
parent
.
create
(
recursive:
true
);
await
goldenFile
.
writeAsBytes
(
imageBytes
,
flush:
true
);
}
/// Calculate the appropriate basedir for the current test context.
@protected
@visibleForTesting
static
Directory
getBaseDirectory
(
GoldensClient
goldens
,
LocalFileComparator
defaultComparator
)
{
final
FileSystem
fs
=
goldens
.
fs
;
final
Directory
testDirectory
=
fs
.
directory
(
defaultComparator
.
basedir
);
final
String
testDirectoryRelativePath
=
fs
.
path
.
relative
(
testDirectory
.
path
,
from:
goldens
.
flutterRoot
.
path
);
return
goldens
.
comparisonRoot
.
childDirectory
(
testDirectoryRelativePath
);
}
/// Returns the golden [File] identified by the given [Uri].
@protected
File
getGoldenFile
(
Uri
uri
)
{
assert
(
basedir
.
scheme
==
'file'
);
final
File
goldenFile
=
fs
.
directory
(
basedir
).
childFile
(
fs
.
file
(
uri
).
path
);
assert
(
goldenFile
.
uri
.
scheme
==
'file'
);
return
goldenFile
;
}
}
/// A [FlutterGoldenFileComparator] for testing golden images against the
/// `flutter/goldens` repository.
///
/// Within the https://github.com/flutter/flutter repository, it's important
/// not to check-in binaries in order to keep the size of the repository to a
/// minimum. To satisfy this requirement, this comparator retrieves the golden
/// files from a sibling repository, `flutter/goldens`.
///
/// This comparator will locally clone the `flutter/goldens` repository into
/// the `$FLUTTER_ROOT/bin/cache/pkg/goldens` folder using the
/// [GoldensRepositoryClient], then perform the comparison against the files
/// therein.
///
/// See also:
///
/// * [GoldenFileComparator], the abstract class that
/// [FlutterGoldenFileComparator] implements.
/// * [FlutterSkiaGoldFileComparator], another [FlutterGoldenFileComparator]
/// that tests golden images through Skia Gold.
class
FlutterGoldensRepositoryFileComparator
extends
FlutterGoldenFileComparator
{
/// Creates a [FlutterGoldensRepositoryFileComparator] that will test golden
/// file images against the `flutter/goldens` repository.
///
/// The [fs] and [platform] parameters useful in tests, where the default file
/// system and platform can be replaced by mock instances.
FlutterGoldensRepositoryFileComparator
(
Uri
basedir
,
{
FileSystem
fs
=
const
LocalFileSystem
(),
Platform
platform
=
const
LocalPlatform
(),
})
:
super
(
basedir
,
fs:
fs
,
platform:
platform
,
);
/// Creates a new [FlutterGoldensRespositoryFileComparator] that mirrors the
/// relative path resolution of the default [goldenFileComparator].
///
/// By the time the future completes, the clone of the `flutter/goldens`
/// repository is guaranteed to be ready use.
/// repository is guaranteed to be ready
to
use.
///
/// The [goldens] and [defaultComparator] parameters are visible for testing
/// purposes only.
static
Future
<
FlutterGoldenFileComparator
>
fromDefaultComparator
({
GoldensClient
goldens
,
static
Future
<
FlutterGolden
sRepository
FileComparator
>
fromDefaultComparator
({
Goldens
Repository
Client
goldens
,
LocalFileComparator
defaultComparator
,
})
async
{
defaultComparator
??=
goldenFileComparator
;
// Prepare the goldens repo.
goldens
??=
GoldensClient
();
goldens
??=
Goldens
Repository
Client
();
await
goldens
.
prepare
();
// Calculate the appropriate basedir for the current test context.
final
FileSystem
fs
=
goldens
.
fs
;
final
Directory
testDirectory
=
fs
.
directory
(
defaultComparator
.
basedir
);
final
String
testDirectoryRelativePath
=
fs
.
path
.
relative
(
testDirectory
.
path
,
from:
goldens
.
flutterRoot
.
path
);
return
FlutterGoldenFileComparator
(
goldens
.
repositoryRoot
.
childDirectory
(
testDirectoryRelativePath
).
uri
);
final
Directory
baseDirectory
=
FlutterGoldenFileComparator
.
getBaseDirectory
(
goldens
,
defaultComparator
);
return
FlutterGoldensRepositoryFileComparator
(
baseDirectory
.
uri
);
}
@override
Future
<
bool
>
compare
(
Uint8List
imageBytes
,
Uri
golden
)
async
{
final
File
goldenFile
=
_
getGoldenFile
(
golden
);
final
File
goldenFile
=
getGoldenFile
(
golden
);
if
(!
goldenFile
.
existsSync
())
{
throw
TestFailure
(
'Could not be compared against non-existent file: "
$golden
"'
);
}
final
List
<
int
>
goldenBytes
=
await
goldenFile
.
readAsBytes
();
// TODO(tvolkert): Improve the intelligence of this comparison.
if
(
goldenBytes
.
length
!=
imageBytes
.
length
)
{
return
false
;
}
...
...
@@ -93,14 +164,134 @@ class FlutterGoldenFileComparator implements GoldenFileComparator {
return
true
;
}
/// Decides based on the current platform whether goldens tests should be
/// performed against the flutter/goldens repository.
static
bool
isAvailableOnPlatform
(
Platform
platform
)
=>
platform
.
isLinux
;
}
/// A [FlutterGoldenFileComparator] for testing golden images with Skia Gold.
///
/// For testing across all platforms, the [SkiaGoldClient] is used to upload
/// images for framework-related golden tests and process results. Currently
/// these tests are designed to be run post-submit on Cirrus CI, informed by the
/// environment.
///
/// See also:
///
/// * [GoldenFileComparator], the abstract class that
/// [FlutterGoldenFileComparator] implements.
/// * [FlutterGoldensRepositoryFileComparator], another
/// [FlutterGoldenFileComparator] that tests golden images using the
/// flutter/goldens repository.
class
FlutterSkiaGoldFileComparator
extends
FlutterGoldenFileComparator
{
/// Creates a [FlutterSkiaGoldFileComparator] that will test golden file
/// images against Skia Gold.
///
/// The [fs] and [platform] parameters useful in tests, where the default file
/// system and platform can be replaced by mock instances.
FlutterSkiaGoldFileComparator
(
final
Uri
basedir
,
this
.
skiaClient
,
{
FileSystem
fs
=
const
LocalFileSystem
(),
Platform
platform
=
const
LocalPlatform
(),
})
:
super
(
basedir
,
fs:
fs
,
platform:
platform
,
);
final
SkiaGoldClient
skiaClient
;
/// Creates a new [FlutterSkiaGoldFileComparator] that mirrors the relative
/// path resolution of the default [goldenFileComparator].
///
/// The [goldens] and [defaultComparator] parameters are visible for testing
/// purposes only.
static
Future
<
FlutterSkiaGoldFileComparator
>
fromDefaultComparator
({
SkiaGoldClient
goldens
,
LocalFileComparator
defaultComparator
,
})
async
{
defaultComparator
??=
goldenFileComparator
;
goldens
??=
SkiaGoldClient
();
final
Directory
baseDirectory
=
FlutterGoldenFileComparator
.
getBaseDirectory
(
goldens
,
defaultComparator
);
if
(!
baseDirectory
.
existsSync
())
baseDirectory
.
createSync
(
recursive:
true
);
await
goldens
.
auth
(
baseDirectory
);
await
goldens
.
imgtestInit
();
return
FlutterSkiaGoldFileComparator
(
baseDirectory
.
uri
,
goldens
);
}
@override
Future
<
void
>
update
(
Uri
golden
,
Uint8List
imageBytes
)
async
{
final
File
goldenFile
=
_getGoldenFile
(
golden
);
await
goldenFile
.
parent
.
create
(
recursive:
true
);
await
goldenFile
.
writeAsBytes
(
imageBytes
,
flush:
true
);
Future
<
bool
>
compare
(
Uint8List
imageBytes
,
Uri
golden
)
async
{
golden
=
_addPrefix
(
golden
);
await
update
(
golden
,
imageBytes
);
final
File
goldenFile
=
getGoldenFile
(
golden
);
if
(!
goldenFile
.
existsSync
())
{
throw
TestFailure
(
'Could not be compared against non-existent file: "
$golden
"'
);
}
return
await
skiaClient
.
imgtestAdd
(
golden
.
path
,
goldenFile
);
}
@override
Uri
getTestUri
(
Uri
key
,
int
version
)
=>
key
;
/// Decides based on the current environment whether goldens tests should be
/// performed against Skia Gold.
static
bool
isAvailableOnPlatform
(
Platform
platform
)
{
final
String
cirrusCI
=
platform
.
environment
[
'CIRRUS_CI'
]
??
''
;
final
String
cirrusPR
=
platform
.
environment
[
'CIRRUS_PR'
]
??
''
;
final
String
cirrusBranch
=
platform
.
environment
[
'CIRRUS_BRANCH'
]
??
''
;
final
String
goldServiceAccount
=
platform
.
environment
[
'GOLD_SERVICE_ACCOUNT'
]
??
''
;
return
cirrusCI
.
isNotEmpty
&&
cirrusPR
.
isEmpty
&&
cirrusBranch
==
'master'
&&
goldServiceAccount
.
isNotEmpty
;
}
File
_getGoldenFile
(
Uri
uri
)
{
return
fs
.
directory
(
basedir
).
childFile
(
fs
.
file
(
uri
).
path
);
/// Prepends the golden Uri with the library name that encloses the current
/// test.
Uri
_addPrefix
(
Uri
golden
)
{
final
String
prefix
=
basedir
.
pathSegments
[
basedir
.
pathSegments
.
length
-
2
];
return
Uri
.
parse
(
prefix
+
'.'
+
golden
.
toString
());
}
}
/// A [FlutterGoldenFileComparator] for skipping golden image tests when Skia
/// Gold is unavailable or the current platform that is executing tests is not
/// Linux.
///
/// See also:
///
/// * [FlutterGoldensRepositoryFileComparator], another
/// [FlutterGoldenFileComparator] that tests golden images using the
/// flutter/goldens repository.
/// * [FlutterSkiaGoldFileComparator], another [FlutterGoldenFileComparator]
/// that tests golden images through Skia Gold.
class
FlutterSkippingGoldenFileComparator
extends
FlutterGoldenFileComparator
{
/// Creates a [FlutterSkippingGoldenFileComparator] that will skip tests that
/// are not in the right environment for golden file testing.
FlutterSkippingGoldenFileComparator
(
Uri
basedir
)
:
super
(
basedir
);
/// Creates a new [FlutterSkippingGoldenFileComparator] that mirrors the relative
/// path resolution of the default [goldenFileComparator].
static
FlutterSkippingGoldenFileComparator
fromDefaultComparator
({
LocalFileComparator
defaultComparator
,
})
{
defaultComparator
??=
goldenFileComparator
;
return
FlutterSkippingGoldenFileComparator
(
defaultComparator
.
basedir
);
}
@override
Future
<
bool
>
compare
(
Uint8List
imageBytes
,
Uri
golden
)
async
{
print
(
'Skipping "
$golden
" test : Skia Gold is not available in this testing '
'environment and flutter/goldens repository comparison is only available '
'on Linux machines.'
);
return
true
;
}
@override
Future
<
void
>
update
(
Uri
golden
,
Uint8List
imageBytes
)
=>
null
;
}
packages/flutter_goldens/test/flutter_goldens_test.dart
View file @
616794fc
...
...
@@ -34,13 +34,13 @@ void main() {
});
group
(
'GoldensClient'
,
()
{
GoldensClient
goldens
;
Goldens
Repository
Client
goldens
;
setUp
(()
{
goldens
=
GoldensClient
(
goldens
=
Goldens
Repository
Client
(
fs:
fs
,
platform:
platform
,
process:
process
,
platform:
platform
,
);
});
...
...
@@ -60,32 +60,65 @@ void main() {
});
});
group
(
'SkiaGoldClient'
,
()
{
SkiaGoldClient
goldens
;
setUp
(()
{
goldens
=
SkiaGoldClient
(
fs:
fs
,
process:
process
,
platform:
platform
,
);
});
group
(
'auth'
,
()
{
test
(
'performs minimal work if already authorized'
,
()
async
{
final
Directory
workDirectory
=
fs
.
directory
(
'/workDirectory'
)..
createSync
(
recursive:
true
);
fs
.
file
(
'/workDirectory/temp/auth_opt.json'
)..
createSync
(
recursive:
true
);
when
(
process
.
run
(
any
)).
thenAnswer
((
_
)
=>
Future
<
io
.
ProcessResult
>.
value
(
io
.
ProcessResult
(
123
,
0
,
''
,
''
)));
await
goldens
.
auth
(
workDirectory
);
// Verify that we spawned no process calls
final
VerificationResult
verifyProcessRun
=
verifyNever
(
process
.
run
(
captureAny
,
workingDirectory:
captureAnyNamed
(
'workingDirectory'
)));
expect
(
verifyProcessRun
.
callCount
,
0
);
});
});
});
group
(
'FlutterGoldenFileComparator'
,
()
{
test
(
'calculates the basedir correctly'
,
()
async
{
final
MockSkiaGoldClient
goldens
=
MockSkiaGoldClient
();
final
MockLocalFileComparator
defaultComparator
=
MockLocalFileComparator
();
final
Directory
flutterRoot
=
fs
.
directory
(
'/foo'
)..
createSync
(
recursive:
true
);
final
Directory
goldensRoot
=
flutterRoot
.
childDirectory
(
'bar'
)..
createSync
(
recursive:
true
);
when
(
goldens
.
fs
).
thenReturn
(
fs
);
when
(
goldens
.
flutterRoot
).
thenReturn
(
flutterRoot
);
when
(
goldens
.
comparisonRoot
).
thenReturn
(
goldensRoot
);
when
(
defaultComparator
.
basedir
).
thenReturn
(
flutterRoot
.
childDirectory
(
'baz'
).
uri
);
final
Directory
basedir
=
FlutterGoldenFileComparator
.
getBaseDirectory
(
goldens
,
defaultComparator
);
expect
(
basedir
.
uri
,
fs
.
directory
(
'/foo/bar/baz'
).
uri
);
});
});
group
(
'FlutterGoldensRepositoryFileComparator'
,
()
{
MemoryFileSystem
fs
;
FlutterGoldenFileComparator
comparator
;
FlutterGolden
sRepository
FileComparator
comparator
;
setUp
(()
{
fs
=
MemoryFileSystem
();
platform
=
FakePlatform
(
operatingSystem:
'linux'
,
environment:
<
String
,
String
>{
'FLUTTER_ROOT'
:
_kFlutterRoot
},
);
final
Directory
flutterRoot
=
fs
.
directory
(
'/path/to/flutter'
)..
createSync
(
recursive:
true
);
final
Directory
goldensRoot
=
flutterRoot
.
childDirectory
(
'bin/cache/goldens'
)..
createSync
(
recursive:
true
);
final
Directory
testDirectory
=
goldensRoot
.
childDirectory
(
'test/foo/bar'
)..
createSync
(
recursive:
true
);
comparator
=
FlutterGoldenFileComparator
(
testDirectory
.
uri
,
fs:
fs
);
});
group
(
'fromDefaultComparator'
,
()
{
test
(
'calculates the basedir correctly'
,
()
async
{
final
MockGoldensClient
goldens
=
MockGoldensClient
();
final
MockLocalFileComparator
defaultComparator
=
MockLocalFileComparator
();
final
Directory
flutterRoot
=
fs
.
directory
(
'/foo'
)..
createSync
(
recursive:
true
);
final
Directory
goldensRoot
=
flutterRoot
.
childDirectory
(
'bar'
)..
createSync
(
recursive:
true
);
when
(
goldens
.
fs
).
thenReturn
(
fs
);
when
(
goldens
.
flutterRoot
).
thenReturn
(
flutterRoot
);
when
(
goldens
.
repositoryRoot
).
thenReturn
(
goldensRoot
);
when
(
defaultComparator
.
basedir
).
thenReturn
(
flutterRoot
.
childDirectory
(
'baz'
).
uri
);
comparator
=
await
FlutterGoldenFileComparator
.
fromDefaultComparator
(
goldens:
goldens
,
defaultComparator:
defaultComparator
);
expect
(
comparator
.
basedir
,
fs
.
directory
(
'/foo/bar/baz'
).
uri
);
});
comparator
=
FlutterGoldensRepositoryFileComparator
(
testDirectory
.
uri
,
fs:
fs
,
platform:
platform
,
);
});
group
(
'compare'
,
()
{
...
...
@@ -132,9 +165,44 @@ void main() {
expect
(
goldenFile
.
readAsBytesSync
(),
<
int
>[
1
,
2
,
3
]);
});
});
group
(
'getTestUri'
,
()
{
test
(
'incorporates version number'
,
()
{
final
Uri
key
=
comparator
.
getTestUri
(
Uri
.
parse
(
'foo.png'
),
1
);
expect
(
key
,
Uri
.
parse
(
'foo.1.png'
));
});
test
(
'ignores null version number'
,
()
{
final
Uri
key
=
comparator
.
getTestUri
(
Uri
.
parse
(
'foo.png'
),
null
);
expect
(
key
,
Uri
.
parse
(
'foo.png'
));
});
});
});
group
(
'FlutterSkiaGoldFileComparator'
,
()
{
FlutterSkiaGoldFileComparator
comparator
;
setUp
(()
{
final
Directory
flutterRoot
=
fs
.
directory
(
'/path/to/flutter'
)..
createSync
(
recursive:
true
);
final
Directory
goldensRoot
=
flutterRoot
.
childDirectory
(
'bin/cache/goldens'
)..
createSync
(
recursive:
true
);
final
Directory
testDirectory
=
goldensRoot
.
childDirectory
(
'test/foo/bar'
)..
createSync
(
recursive:
true
);
comparator
=
FlutterSkiaGoldFileComparator
(
testDirectory
.
uri
,
MockSkiaGoldClient
(),
fs:
fs
,
platform:
platform
,
);
});
group
(
'getTestUri'
,
()
{
test
(
'ignores version number'
,
()
{
final
Uri
key
=
comparator
.
getTestUri
(
Uri
.
parse
(
'foo.png'
),
1
);
expect
(
key
,
Uri
.
parse
(
'foo.png'
));
});
});
});
}
class
MockProcessManager
extends
Mock
implements
ProcessManager
{}
class
MockGoldensClient
extends
Mock
implements
GoldensClient
{}
class
MockGoldensRepositoryClient
extends
Mock
implements
GoldensRepositoryClient
{}
class
MockSkiaGoldClient
extends
Mock
implements
SkiaGoldClient
{}
class
MockLocalFileComparator
extends
Mock
implements
LocalFileComparator
{}
packages/flutter_goldens_client/lib/client.dart
View file @
616794fc
...
...
@@ -16,11 +16,11 @@ import 'package:process/process.dart';
const
String
_kFlutterRootKey
=
'FLUTTER_ROOT'
;
/// A
class that represents a clone of the https://github.com/flutter/goldens
///
repository, nested within the `bin/cache` directory of the caller's Flutter
///
repository
.
class
GoldensClient
{
/// Create
a handle to a local clone of the goldens repository
.
/// A
base class that provides shared information to the
///
[FlutterGoldenFileComparator] as well as the [SkiaGoldClient] and
///
[GoldensRepositoryClient]
.
abstract
class
GoldensClient
{
/// Create
s a handle to the local environment of golden file images
.
GoldensClient
({
this
.
fs
=
const
LocalFileSystem
(),
this
.
platform
=
const
LocalPlatform
(),
...
...
@@ -46,17 +46,33 @@ class GoldensClient {
/// subprocesses.
final
ProcessManager
process
;
RandomAccessFile
_lock
;
/// The local [Directory] where the Flutter repository is hosted.
///
/// Uses the [fs] file system.
Directory
get
flutterRoot
=>
fs
.
directory
(
platform
.
environment
[
_kFlutterRootKey
]);
/// The local [Directory] where the goldens
repository is hos
ted.
/// The local [Directory] where the goldens
files are loca
ted.
///
/// Uses the [fs] file system.
Directory
get
repositoryRoot
=>
flutterRoot
.
childDirectory
(
fs
.
path
.
join
(
'bin'
,
'cache'
,
'pkg'
,
'goldens'
));
Directory
get
comparisonRoot
=>
flutterRoot
.
childDirectory
(
fs
.
path
.
join
(
'bin'
,
'cache'
,
'pkg'
,
'goldens'
));
}
/// A class that represents a clone of the https://github.com/flutter/goldens
/// repository, nested within the `bin/cache` directory of the caller's Flutter
/// repository.
class
GoldensRepositoryClient
extends
GoldensClient
{
GoldensRepositoryClient
({
FileSystem
fs
=
const
LocalFileSystem
(),
ProcessManager
process
=
const
LocalProcessManager
(),
Platform
platform
=
const
LocalPlatform
(),
})
:
super
(
fs:
fs
,
process:
process
,
platform:
platform
,
);
RandomAccessFile
_lock
;
/// Prepares the local clone of the `flutter/goldens` repository for golden
/// file testing.
...
...
@@ -89,45 +105,45 @@ class GoldensClient {
}
}
Future
<
String
>
_getGoldensCommit
()
async
{
final
File
versionFile
=
flutterRoot
.
childFile
(
fs
.
path
.
join
(
'bin'
,
'internal'
,
'goldens.version'
));
return
(
await
versionFile
.
readAsString
()).
trim
();
}
Future
<
String
>
_getCurrentCommit
()
async
{
if
(!
repository
Root
.
existsSync
())
{
if
(!
comparison
Root
.
existsSync
())
{
return
null
;
}
else
{
final
io
.
ProcessResult
revParse
=
await
process
.
run
(
<
String
>[
'git'
,
'rev-parse'
,
'HEAD'
],
workingDirectory:
repository
Root
.
path
,
workingDirectory:
comparison
Root
.
path
,
);
return
revParse
.
exitCode
==
0
?
revParse
.
stdout
.
trim
()
:
null
;
}
}
Future
<
String
>
_getGoldensCommit
()
async
{
final
File
versionFile
=
flutterRoot
.
childFile
(
fs
.
path
.
join
(
'bin'
,
'internal'
,
'goldens.version'
));
return
(
await
versionFile
.
readAsString
()).
trim
();
}
Future
<
void
>
_initRepository
()
async
{
await
repository
Root
.
create
(
recursive:
true
);
await
comparison
Root
.
create
(
recursive:
true
);
await
_runCommands
(
<
String
>[
'git init'
,
'git remote add upstream https://github.com/flutter/goldens.git'
,
'git remote set-url --push upstream git@github.com:flutter/goldens.git'
,
],
workingDirectory:
repository
Root
,
workingDirectory:
comparison
Root
,
);
}
Future
<
void
>
_checkCanSync
()
async
{
final
io
.
ProcessResult
result
=
await
process
.
run
(
<
String
>[
'git'
,
'status'
,
'--porcelain'
],
workingDirectory:
repository
Root
.
path
,
workingDirectory:
comparison
Root
.
path
,
);
if
(
result
.
stdout
.
trim
().
isNotEmpty
)
{
final
StringBuffer
buf
=
StringBuffer
()
..
writeln
(
'flutter_goldens git checkout at
${
repository
Root.path}
has local changes and cannot be synced.'
)
..
writeln
(
'flutter_goldens git checkout at
${
comparison
Root.path}
has local changes and cannot be synced.'
)
..
writeln
(
'To reset your client to a clean state, and lose any local golden test changes:'
)
..
writeln
(
'cd
${
repository
Root.path}
'
)
..
writeln
(
'cd
${
comparison
Root.path}
'
)
..
writeln
(
'git reset --hard HEAD'
)
..
writeln
(
'git clean -x -d -f -f'
);
throw
NonZeroExitCode
(
1
,
buf
.
toString
());
...
...
@@ -141,7 +157,7 @@ class GoldensClient {
'git fetch upstream
$commit
'
,
'git reset --hard FETCH_HEAD'
,
],
workingDirectory:
repository
Root
,
workingDirectory:
comparison
Root
,
);
}
...
...
@@ -173,6 +189,7 @@ class GoldensClient {
_lock
=
null
;
}
}
/// Exception that signals a process' exit with a non-zero exit code.
class
NonZeroExitCode
implements
Exception
{
/// Create an exception that represents a non-zero exit code.
...
...
packages/flutter_goldens_client/lib/skia_client.dart
0 → 100644
View file @
616794fc
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:convert'
;
import
'dart:io'
as
io
;
import
'package:file/file.dart'
;
import
'package:file/local.dart'
;
import
'package:path/path.dart'
as
path
;
import
'package:platform/platform.dart'
;
import
'package:process/process.dart'
;
import
'package:flutter_goldens_client/client.dart'
;
// If you are here trying to figure out how to use golden files in the Flutter
// repo itself, consider reading this wiki page:
// https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package%3Aflutter
// TODO(Piinks): This file will replace ./client.dart when transition to Skia
// Gold testing is complete
const
String
_kGoldctlKey
=
'GOLDCTL'
;
const
String
_kServiceAccountKey
=
'GOLD_SERVICE_ACCOUNT'
;
/// An extension of the [GoldensClient] class that interfaces with Skia Gold
/// for golden file testing.
class
SkiaGoldClient
extends
GoldensClient
{
SkiaGoldClient
({
FileSystem
fs
=
const
LocalFileSystem
(),
ProcessManager
process
=
const
LocalProcessManager
(),
Platform
platform
=
const
LocalPlatform
(),
})
:
super
(
fs:
fs
,
process:
process
,
platform:
platform
,
);
/// The local [Directory] within the [comparisonRoot] for the current test
/// context. In this directory, the client will create image and json files
/// for the goldctl tool to use.
///
/// This is informed by the [FlutterGoldenFileComparator] [basedir]. It cannot
/// be null.
Directory
_workDirectory
;
/// The path to the local [Directory] where the goldctl tool is hosted.
///
/// Uses the [platform] environment in this implementation.
String
get
_goldctl
=>
platform
.
environment
[
_kGoldctlKey
];
/// The path to the local [Directory] where the service account key is
/// hosted.
///
/// Uses the [platform] environment in this implementation.
String
get
_serviceAccount
=>
platform
.
environment
[
_kServiceAccountKey
];
@override
Directory
get
comparisonRoot
=>
flutterRoot
.
childDirectory
(
fs
.
path
.
join
(
'bin'
,
'cache'
,
'pkg'
,
'skia_goldens'
));
/// Prepares the local work space for golden file testing and calls the
/// goldctl `auth` command.
///
/// This ensures that the goldctl tool is authorized and ready for testing. It
/// will only be called once for each instance of
/// [FlutterSkiaGoldFileComparator].
///
/// The [workDirectory] parameter specifies the current directory that golden
/// tests are executing in, relative to the library of the given test. It is
/// informed by the basedir of the [FlutterSkiaGoldFileComparator].
Future
<
void
>
auth
(
Directory
workDirectory
)
async
{
assert
(
workDirectory
!=
null
);
_workDirectory
=
workDirectory
;
if
(
_clientIsAuthorized
())
return
;
if
(
_serviceAccount
.
isEmpty
)
{
final
StringBuffer
buf
=
StringBuffer
()..
writeln
(
'Gold service account is unavailable.'
);
throw
NonZeroExitCode
(
1
,
buf
.
toString
());
}
final
File
authorization
=
_workDirectory
.
childFile
(
'serviceAccount.json'
);
await
authorization
.
writeAsString
(
_serviceAccount
);
final
List
<
String
>
authArguments
=
<
String
>[
'auth'
,
'--service-account'
,
authorization
.
path
,
'--work-dir'
,
_workDirectory
.
childDirectory
(
'temp'
).
path
,
];
// final io.ProcessResult authResults =
await
io
.
Process
.
run
(
_goldctl
,
authArguments
,
);
// TODO(Piinks): Re-enable after Gold flakes are resolved, https://github.com/flutter/flutter/pull/36103
// if (authResults.exitCode != 0) {
// final StringBuffer buf = StringBuffer()
// ..writeln('Flutter + Skia Gold auth failed.')
// ..writeln('stdout: ${authResults.stdout}')
// ..writeln('stderr: ${authResults.stderr}');
// throw NonZeroExitCode(authResults.exitCode, buf.toString());
// }
}
/// Executes the `imgtest init` command in the goldctl tool.
///
/// The `imgtest` command collects and uploads test results to the Skia Gold
/// backend, the `init` argument initializes the current test.
Future
<
void
>
imgtestInit
()
async
{
final
File
keys
=
_workDirectory
.
childFile
(
'keys.json'
);
final
File
failures
=
_workDirectory
.
childFile
(
'failures.json'
);
await
keys
.
writeAsString
(
_getKeysJSON
());
await
failures
.
create
();
final
String
commitHash
=
await
_getCurrentCommit
();
final
List
<
String
>
imgtestInitArguments
=
<
String
>[
'imgtest'
,
'init'
,
'--instance'
,
'flutter'
,
'--work-dir'
,
_workDirectory
.
childDirectory
(
'temp'
).
path
,
'--commit'
,
commitHash
,
'--keys-file'
,
keys
.
path
,
'--failure-file'
,
failures
.
path
,
'--passfail'
,
];
if
(
imgtestInitArguments
.
contains
(
null
))
{
final
StringBuffer
buf
=
StringBuffer
();
buf
.
writeln
(
'Null argument for Skia Gold imgtest init:'
);
imgtestInitArguments
.
forEach
(
buf
.
writeln
);
throw
NonZeroExitCode
(
1
,
buf
.
toString
());
}
// final io.ProcessResult imgtestInitResult =
await
io
.
Process
.
run
(
_goldctl
,
imgtestInitArguments
,
);
// TODO(Piinks): Re-enable after Gold flakes are resolved, https://github.com/flutter/flutter/pull/36103
// if (imgtestInitResult.exitCode != 0) {
// final StringBuffer buf = StringBuffer()
// ..writeln('Flutter + Skia Gold imgtest init failed.')
// ..writeln('stdout: ${imgtestInitResult.stdout}')
// ..writeln('stderr: ${imgtestInitResult.stderr}');
// throw NonZeroExitCode(imgtestInitResult.exitCode, buf.toString());
// }
}
/// Executes the `imgtest add` command in the goldctl tool.
///
/// The `imgtest` command collects and uploads test results to the Skia Gold
/// backend, the `add` argument uploads the current image test. A response is
/// returned from the invocation of this command that indicates a pass or fail
/// result.
///
/// The testName and goldenFile parameters reference the current comparison
/// being evaluated by the [FlutterSkiaGoldFileComparator].
Future
<
bool
>
imgtestAdd
(
String
testName
,
File
goldenFile
)
async
{
assert
(
testName
!=
null
);
assert
(
goldenFile
!=
null
);
final
List
<
String
>
imgtestArguments
=
<
String
>[
'imgtest'
,
'add'
,
'--work-dir'
,
_workDirectory
.
childDirectory
(
'temp'
).
path
,
'--test-name'
,
testName
.
split
(
path
.
extension
(
testName
.
toString
()))[
0
],
'--png-file'
,
goldenFile
.
path
,
];
await
io
.
Process
.
run
(
_goldctl
,
imgtestArguments
,
);
// TODO(Piinks): Comment on PR if triage is needed, https://github.com/flutter/flutter/issues/34673
// So as not to turn the tree red in this initial implementation, this will
// return true for now.
// The ProcessResult that returns from line 157 contains the pass/fail
// result of the test & links to the dashboard and diffs.
return
true
;
}
/// Returns the current commit hash of the Flutter repository.
Future
<
String
>
_getCurrentCommit
()
async
{
if
(!
flutterRoot
.
existsSync
())
{
final
StringBuffer
buf
=
StringBuffer
()
..
writeln
(
'Flutter root could not be found:
$flutterRoot
'
);
throw
NonZeroExitCode
(
1
,
buf
.
toString
());
}
else
{
final
io
.
ProcessResult
revParse
=
await
process
.
run
(
<
String
>[
'git'
,
'rev-parse'
,
'HEAD'
],
workingDirectory:
flutterRoot
.
path
,
);
return
revParse
.
exitCode
==
0
?
revParse
.
stdout
.
trim
()
:
null
;
}
}
/// Returns a JSON String with keys value pairs used to uniquely identify the
/// configuration that generated the given golden file.
///
/// Currently, the only key value pair being tracked is the platform the image
/// was rendered on.
String
_getKeysJSON
()
{
return
json
.
encode
(
<
String
,
dynamic
>{
'Platform'
:
platform
.
operatingSystem
,
}
);
}
/// Returns a boolean value to prevent the client from re-authorizing itself
/// for multiple tests.
bool
_clientIsAuthorized
()
{
final
File
authFile
=
_workDirectory
?.
childFile
(
super
.
fs
.
path
.
join
(
'temp'
,
'auth_opt.json'
,
));
return
authFile
.
existsSync
();
}
}
packages/flutter_test/lib/src/goldens.dart
View file @
616794fc
...
...
@@ -45,6 +45,26 @@ abstract class GoldenFileComparator {
/// The method by which [golden] is located and by which its bytes are written
/// is left up to the implementation class.
Future
<
void
>
update
(
Uri
golden
,
Uint8List
imageBytes
);
/// Returns a new golden file [Uri] to incorporate any [version] number with
/// the [key].
///
/// The [version] is an optional int that can be used to differentiate
/// historical golden files.
///
/// Version numbers are used in golden file tests for package:flutter. You can
/// learn more about these tests [here](https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter).
Uri
getTestUri
(
Uri
key
,
int
version
)
{
if
(
version
==
null
)
return
key
;
final
String
keyString
=
key
.
toString
();
final
String
extension
=
path
.
extension
(
keyString
);
return
Uri
.
parse
(
keyString
.
split
(
extension
)
.
join
()
+
'.'
+
version
.
toString
()
+
extension
);
}
}
/// Compares rasterized image bytes against a golden image file.
...
...
@@ -126,6 +146,11 @@ class TrivialComparator implements GoldenFileComparator {
Future
<
void
>
update
(
Uri
golden
,
Uint8List
imageBytes
)
{
throw
StateError
(
'goldenFileComparator has not been initialized'
);
}
@override
Uri
getTestUri
(
Uri
key
,
int
version
)
{
return
key
;
}
}
/// The default [GoldenFileComparator] implementation for `flutter test`.
...
...
@@ -140,7 +165,7 @@ class TrivialComparator implements GoldenFileComparator {
///
/// When using `flutter test --update-goldens`, [LocalFileComparator]
/// updates the files on disk to match the rendering.
class
LocalFileComparator
implement
s
GoldenFileComparator
{
class
LocalFileComparator
extend
s
GoldenFileComparator
{
/// Creates a new [LocalFileComparator] for the specified [testFile].
///
/// Golden file keys will be interpreted as file paths relative to the
...
...
packages/flutter_test/lib/src/matchers.dart
View file @
616794fc
...
...
@@ -1715,7 +1715,7 @@ class _MatchesGoldenFile extends AsyncMatcher {
imageFuture
=
_captureImage
(
elements
.
single
);
}
final
Uri
testNameUri
=
_getTestName
Uri
(
key
,
version
);
final
Uri
testNameUri
=
goldenFileComparator
.
getTest
Uri
(
key
,
version
);
final
TestWidgetsFlutterBinding
binding
=
TestWidgetsFlutterBinding
.
ensureInitialized
();
return
binding
.
runAsync
<
String
>(()
async
{
...
...
@@ -1737,19 +1737,9 @@ class _MatchesGoldenFile extends AsyncMatcher {
}
@override
Description
describe
(
Description
description
)
=>
description
.
add
(
'one widget whose rasterized image matches golden image "
${_getTestNameUri(key, version)}
"'
);
Uri
_getTestNameUri
(
Uri
key
,
int
version
)
{
return
version
==
null
?
key
:
Uri
.
parse
(
key
.
toString
()
.
splitMapJoin
(
RegExp
(
r'.png'
),
onMatch:
(
Match
m
)
=>
'
${'.' + version.toString() + m.group(0)}
'
,
onNonMatch:
(
String
n
)
=>
'
$n
'
)
);
Description
describe
(
Description
description
)
{
final
Uri
testNameUri
=
goldenFileComparator
.
getTestUri
(
key
,
version
);
return
description
.
add
(
'one widget whose rasterized image matches golden image "
$testNameUri
"'
);
}
}
...
...
packages/flutter_test/test/goldens_test.dart
View file @
616794fc
...
...
@@ -182,5 +182,18 @@ void main() {
expect
(
fs
.
file
(
fix
(
'/foo.png'
)).
readAsBytesSync
(),
newBytes
);
});
});
group
(
'getTestUri'
,
()
{
test
(
'updates file name with version number'
,
()
{
final
Uri
key
=
Uri
.
parse
(
'foo.png'
);
final
Uri
key1
=
comparator
.
getTestUri
(
key
,
1
);
expect
(
key1
,
Uri
.
parse
(
'foo.1.png'
));
});
test
(
'does nothing for null version number'
,
()
{
final
Uri
key
=
Uri
.
parse
(
'foo.png'
);
final
Uri
keyNull
=
comparator
.
getTestUri
(
key
,
null
);
expect
(
keyNull
,
Uri
.
parse
(
'foo.png'
));
});
});
});
}
packages/flutter_test/test/matchers_test.dart
View file @
616794fc
...
...
@@ -335,30 +335,6 @@ void main() {
expect
(
comparator
.
imageBytes
,
hasLength
(
greaterThan
(
0
)));
expect
(
comparator
.
golden
,
Uri
.
parse
(
'foo.png'
));
});
testWidgets
(
'Comparator succeeds incorporating version number'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
boilerplate
(
const
Text
(
'hello'
)));
final
Finder
finder
=
find
.
byType
(
Text
);
await
expectLater
(
finder
,
matchesGoldenFile
(
'foo.png'
,
version:
1
,
));
expect
(
comparator
.
invocation
,
_ComparatorInvocation
.
compare
);
expect
(
comparator
.
imageBytes
,
hasLength
(
greaterThan
(
0
)));
expect
(
comparator
.
golden
,
Uri
.
parse
(
'foo.1.png'
));
});
testWidgets
(
'Comparator succeeds with null version number'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
boilerplate
(
const
Text
(
'hello'
)));
final
Finder
finder
=
find
.
byType
(
Text
);
await
expectLater
(
finder
,
matchesGoldenFile
(
'foo.png'
,
version:
null
,
));
expect
(
comparator
.
invocation
,
_ComparatorInvocation
.
compare
);
expect
(
comparator
.
imageBytes
,
hasLength
(
greaterThan
(
0
)));
expect
(
comparator
.
golden
,
Uri
.
parse
(
'foo.png'
));
});
});
group
(
'does not match'
,
()
{
...
...
@@ -413,40 +389,6 @@ void main() {
expect
(
error
.
message
,
contains
(
'too many widgets'
));
}
});
testWidgets
(
'Comparator failure incorporates version number'
,
(
WidgetTester
tester
)
async
{
comparator
.
behavior
=
_ComparatorBehavior
.
returnFalse
;
await
tester
.
pumpWidget
(
boilerplate
(
const
Text
(
'hello'
)));
final
Finder
finder
=
find
.
byType
(
Text
);
try
{
await
expectLater
(
finder
,
matchesGoldenFile
(
'foo.png'
,
version:
1
,
));
fail
(
'TestFailure expected but not thrown'
);
}
on
TestFailure
catch
(
error
)
{
expect
(
comparator
.
invocation
,
_ComparatorInvocation
.
compare
);
expect
(
error
.
message
,
contains
(
'does not match'
));
expect
(
error
.
message
,
contains
(
'foo.1.png'
));
}
});
testWidgets
(
'Comparator failure with null version number'
,
(
WidgetTester
tester
)
async
{
comparator
.
behavior
=
_ComparatorBehavior
.
returnFalse
;
await
tester
.
pumpWidget
(
boilerplate
(
const
Text
(
'hello'
)));
final
Finder
finder
=
find
.
byType
(
Text
);
try
{
await
expectLater
(
finder
,
matchesGoldenFile
(
'foo.png'
,
version:
null
,
));
fail
(
'TestFailure expected but not thrown'
);
}
on
TestFailure
catch
(
error
)
{
expect
(
comparator
.
invocation
,
_ComparatorInvocation
.
compare
);
expect
(
error
.
message
,
contains
(
'does not match'
));
expect
(
error
.
message
,
contains
(
'foo.png'
));
}
});
});
testWidgets
(
'calls update on comparator if autoUpdateGoldenFiles is true'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -712,6 +654,11 @@ class _FakeComparator implements GoldenFileComparator {
this
.
imageBytes
=
imageBytes
;
return
Future
<
void
>.
value
();
}
@override
Uri
getTestUri
(
Uri
key
,
int
version
)
{
return
key
;
}
}
class
_FakeSemanticsNode
extends
SemanticsNode
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment