Skip to content

Commit

Permalink
Added integration test for wide gamut support. (#119657)
Browse files Browse the repository at this point in the history
* Added integration test for wide gamut support.

* cleaned up

* deleted files that can be generated

* switched back to standard flutter in the shell script

* added devicelab task

* removed analysis options

* analyzer

* Fixed task

* made local_run.sh not executable

* analyzer

* removed the logo asset

* added task to ci

* updated pubspec

* analysis errors fixed

* updated pubspec
  • Loading branch information
gaaclarke authored Feb 13, 2023
1 parent 778b3fa commit ddebe83
Show file tree
Hide file tree
Showing 11 changed files with 393 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3898,6 +3898,16 @@ targets:
["devicelab", "ios", "mac"]
task_name: simple_animation_perf_ios

- name: Mac_ios wide_gamut_ios
recipe: devicelab/devicelab_drone
bringup: true
presubmit: false
timeout: 60
properties:
tags: >
["devicelab", "ios", "mac"]
task_name: wide_gamut_ios

- name: Mac_ios simple_animation_perf_impeller_ios
recipe: devicelab/devicelab_drone
presubmit: false
Expand Down
1 change: 1 addition & 0 deletions TESTOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
/dev/devicelab/bin/tasks/animated_complex_opacity_perf__e2e_summary.dart @jonahwilliams @flutter/engine
/dev/devicelab/bin/tasks/animated_complex_image_filtered_perf__e2e_summary.dart @jonahwilliams @flutter/engine
/dev/devicelab/bin/tasks/spell_check_test.dart @camsim99 @flutter/android
/dev/devicelab/bin/tasks/wide_gamut_ios.dart @gaaclarke @flutter/engine

## Windows Android DeviceLab tests
/dev/devicelab/bin/tasks/basic_material_app_win__compile.dart @zanderso @flutter/tool
Expand Down
12 changes: 12 additions & 0 deletions dev/devicelab/bin/tasks/wide_gamut_ios.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// 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.

import 'package:flutter_devicelab/framework/devices.dart';
import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/tasks/integration_tests.dart';

Future<void> main() async {
deviceOperatingSystem = DeviceOperatingSystem.ios;
await task(createWideGamutTest());
}
19 changes: 19 additions & 0 deletions dev/devicelab/lib/tasks/integration_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ TaskFunction createWindowsStartupDriverTest({String? deviceIdOverride}) {
).call;
}

TaskFunction createWideGamutTest() {
return IntegrationTest(
'${flutterDirectory.path}/dev/integration_tests/wide_gamut_test',
'integration_test/app_test.dart',
createPlatforms: <String>['ios'],
).call;
}

class DriverTest {
DriverTest(
this.testDirectory,
Expand Down Expand Up @@ -204,12 +212,14 @@ class IntegrationTest {
this.testDirectory,
this.testTarget, {
this.extraOptions = const <String>[],
this.createPlatforms = const <String>[],
}
);

final String testDirectory;
final String testTarget;
final List<String> extraOptions;
final List<String> createPlatforms;

Future<TaskResult> call() {
return inDirectory<TaskResult>(testDirectory, () async {
Expand All @@ -218,6 +228,15 @@ class IntegrationTest {
final String deviceId = device.deviceId;
await flutter('packages', options: <String>['get']);

if (createPlatforms.isNotEmpty) {
await flutter('create', options: <String>[
'--platforms',
createPlatforms.join(','),
'--no-overwrite',
'.'
]);
}

final List<String> options = <String>[
'-v',
'-d',
Expand Down
44 changes: 44 additions & 0 deletions dev/integration_tests/wide_gamut_test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/

# IntelliJ related
*.iml
*.ipr
*.iws
.idea/

# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/

# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/

# Symbolication related
app.*.symbols

# Obfuscation related
app.*.map.json

# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
30 changes: 30 additions & 0 deletions dev/integration_tests/wide_gamut_test/.metadata
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.

version:
revision: c379133df6d1f8893ad8c9d0393496c7d6eaf828
channel: wide-gamut-integration-test

project_type: app

# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: c379133df6d1f8893ad8c9d0393496c7d6eaf828
base_revision: c379133df6d1f8893ad8c9d0393496c7d6eaf828
- platform: ios
create_revision: c379133df6d1f8893ad8c9d0393496c7d6eaf828
base_revision: c379133df6d1f8893ad8c9d0393496c7d6eaf828

# User provided section

# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
10 changes: 10 additions & 0 deletions dev/integration_tests/wide_gamut_test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# wide_gamut_test

An integration test used for testing wide gamut color support in the engine.

## Local run

```sh
flutter create --platforms="ios" --no-overwrite .
flutter test integration_test/app_test.dart
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// 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.

import 'dart:typed_data';

import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

import 'package:wide_gamut_test/main.dart' as app;

// See: https://developer.apple.com/documentation/metal/mtlpixelformat/mtlpixelformatbgr10_xr.
double _decodeBGR10(int x) {
const double max = 1.25098;
const double min = -0.752941;
const double intercept = min;
const double slope = (max - min) / 1024.0;
return (x * slope) + intercept;
}

bool _isAlmost(double x, double y, double epsilon) {
return (x - y).abs() < epsilon;
}

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

group('end-to-end test', () {
testWidgets('look for display p3 deepest red', (WidgetTester tester) async {
app.main();
await tester.pumpAndSettle(const Duration(seconds: 2));

const MethodChannel channel = MethodChannel('flutter/screenshot');
final List<Object?> result =
await channel.invokeMethod('test') as List<Object?>;
expect(result, isNotNull);
expect(result.length, 4);
final int width = (result[0] as int?)!;
final int height = (result[1] as int?)!;
final String format = (result[2] as String?)!;
expect(format, 'MTLPixelFormatBGR10_XR');
final Uint8List bytes = (result[3] as Uint8List?)!;
final ByteData byteData = ByteData.sublistView(bytes);
expect(bytes.lengthInBytes, width * height * 4);
expect(bytes.lengthInBytes, byteData.lengthInBytes);
bool foundDeepRed = false;
for (int i = 0; i < bytes.lengthInBytes; i += 4) {
final int pixel = byteData.getUint32(i, Endian.host);
final double blue = _decodeBGR10(pixel & 0x3ff);
final double green = _decodeBGR10((pixel >> 10) & 0x3ff);
final double red = _decodeBGR10((pixel >> 20) & 0x3ff);
if (_isAlmost(red, 1.0931, 0.01) &&
_isAlmost(green, -0.2268, 0.01) &&
_isAlmost(blue, -0.1501, 0.01)) {
foundDeepRed = true;
}
}
expect(foundDeepRed, isTrue);
});
});
}
55 changes: 55 additions & 0 deletions dev/integration_tests/wide_gamut_test/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Wide Gamut Test</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>wide_gamut_test</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>FLTEnableImpeller</key>
<true/>
<key>FLTEnableWideGamut</key>
<true/>
</dict>
</plist>
106 changes: 106 additions & 0 deletions dev/integration_tests/wide_gamut_test/lib/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// 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.

import 'dart:convert' show base64Decode;
import 'package:flutter/material.dart';

/// A 100x100 png in Display P3 colorspace.
const String _displayP3Logo =
'iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAABdWlDQ1BrQ0dDb2xvclNwYWNlRG'
'lzcGxheVAzAAAokXWQvUvDUBTFT6tS0DqIDh0cMolD1NIKdnFoKxRFMFQFq1OafgltfCQpUnET'
'Vyn4H1jBWXCwiFRwcXAQRAcR3Zw6KbhoeN6XVNoi3sfl/Ticc7lcwBtQGSv2AijplpFMxKS11L'
'rke4OHnlOqZrKooiwK/v276/PR9d5PiFlNu3YQ2U9cl84ul3aeAlN//V3Vn8maGv3f1EGNGRbg'
'kYmVbYsJ3iUeMWgp4qrgvMvHgtMunzuelWSc+JZY0gpqhrhJLKc79HwHl4plrbWD2N6f1VeXxR'
'zqUcxhEyYYilBRgQQF4X/8044/ji1yV2BQLo8CLMpESRETssTz0KFhEjJxCEHqkLhz634PrfvJ'
'bW3vFZhtcM4v2tpCAzidoZPV29p4BBgaAG7qTDVUR+qh9uZywPsJMJgChu8os2HmwiF3e38M6H'
'vh/GMM8B0CdpXzryPO7RqFn4Er/QcXKWq8UwZBywAAAJplWElmTU0AKgAAAAgABQESAAMAAAAB'
'AAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgExAAIAAAAhAAAAWodpAAQAAAABAAAAfAAAAA'
'AAAABIAAAAAQAAAEgAAAABQWRvYmUgUGhvdG9zaG9wIDI0LjEgKE1hY2ludG9zaCkAAAACoAIA'
'BAAAAAEAAABkoAMABAAAAAEAAABkAAAAALGpdjYAAAAJcEhZcwAACxMAAAsTAQCanBgAAAR2aV'
'RYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1l'
'dGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaH'
'R0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6'
'RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly'
'9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDov'
'L25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RSZWY9Imh0dH'
'A6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiCiAgICAgICAgICAg'
'IHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx0aW'
'ZmOllSZXNvbHV0aW9uPjcyPC90aWZmOllSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpYUmVz'
'b2x1dGlvbj43MjwvdGlmZjpYUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb2'
'4+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHhtcE1NOkRlcml2ZWRGcm9tIHJkZjpw'
'YXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgPHN0UmVmOmluc3RhbmNlSUQ+eG1wLm'
'lpZDpDREE0Mzc3NzhBRjcxMUVEQTU0N0JCNjBEMjUwOTI2RDwvc3RSZWY6aW5zdGFuY2VJRD4K'
'ICAgICAgICAgICAgPHN0UmVmOmRvY3VtZW50SUQ+eG1wLmRpZDpDREE0Mzc3ODhBRjcxMUVEQT'
'U0N0JCNjBEMjUwOTI2RDwvc3RSZWY6ZG9jdW1lbnRJRD4KICAgICAgICAgPC94bXBNTTpEZXJp'
'dmVkRnJvbT4KICAgICAgICAgPHhtcE1NOkRvY3VtZW50SUQ+eG1wLmRpZDpDREE0Mzc3QThBRj'
'cxMUVEQTU0N0JCNjBEMjUwOTI2RDwveG1wTU06RG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1N'
'Okluc3RhbmNlSUQ+eG1wLmlpZDpDREE0Mzc3OThBRjcxMUVEQTU0N0JCNjBEMjUwOTI2RDwveG'
'1wTU06SW5zdGFuY2VJRD4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3No'
'b3AgMjQuMSAoTWFjaW50b3NoKTwveG1wOkNyZWF0b3JUb29sPgogICAgICA8L3JkZjpEZXNjcm'
'lwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KRm6gbQAABNpJREFUeAHtnOty3CAM'
'hZO2Pzrt+z9qO/3RS/iSOVPGwcTrFZLwoqlDfUPifAgc75Lnf09P5d+yLAp8yhLIiuNNgQUkWU'
'9YQBaQZAokC2dlyAKSTIFk4awMWUCSKZAsnJUhyYB8SRbPkHB4FfG3bM8DaqduerVV3ZcFglCI'
'9KdsP8tm/X6IuoH8uWzfyraAFBH2rIbxo1yk/b3rzxwXjO/lZisYxHG5OUTikxmjYOCDzLCGUa'
'q8FpDZYVwKSAQMfFrbJYasKBiWc4fATg8kAgbijYBBvVMDiYKBcKNsWiARMPA52qYEEgVj1DBV'
'Q54OSAQMBPOAgZ+pgETA8BimACGbBkgUDK/MmArIo8AAynNprHdWqjPcVM76buqmRpaLUw9Z6i'
'meMOTzViGtrk8LBGEYv71heM8ZW5ApgUTAQJhoGMSQDkgUDMTIYKmARMDAZyZLAyQKRoZhqu4Q'
'KYBEwECEbDCIKRxIFAwan9FCgUTAwGdmCwMSBSPjMFV3kBAgETBodHYYxOgOJAJG9mEKEDJXIF'
'EwZsgMdyALhiTvly4ZsmD0IdRnhwOJgEEDZxqm3IBEwMDnzDYsQ6JgzJoZ6kRDgCwYkvf20hxI'
'BAyaPXtmCJ3pkrYIGPKpBrVKrhm5xpDOYNWzTYEQWJbPwAWKeDzWGBY3JmYF9jUYTxg43Bumtj'
'DIDmujTsRjwaeliGYZ4g2jJ7B3pvZiufWcGVzLcbRuBL396AJLrsUydY63iI7/NANCRaxKRTwJ'
'czyM9pVbGL16OeedGb142i36+KgZEFwhCGOqBZQWDOpvWQ1DE/jeta37jxzbxsM91j6o0xQIQV'
'tkyi2Nr2GwLn3E463isfyLDYjfMlMg9BgJdHb4UuO1KJ/9PZMvrznDVKydRpn7uAdKC8besOAN'
'Q+3a0dHssDkQIlPwlEczZQtD9VBuLQrGXufYxnfP/hAgBHQLlBaMvUZFwFB79mKyPD4MiBohAf'
'cy5SwMr6cp4vO0oUBoSC9TtjB6jeccdWkCH/k0VT9QeAxT6CRzW9ImQSl5PP1dNt7bqPHlv7um'
'ewVD+7s3nDhBnUffCJyo/vAtbkCISELSu3+V7WvZPkpR3fMIMIocuRd9RsCQT8SJsI86aERMrz'
'4lDJnhOYF7zxlbgc1ev28rvme/huH5Z/qiYaBZugyJgnFPB7K8Nx0QeimT/sjMoNF6uqMDZLJ0'
'Q5bn05SyMROQlBkyciwHAhmY1Vx/DzkqAqIxZJEt1nCUFfWrHGsfR9vZui5dhrQEawV+9hjib4'
'Gzn8XSAZFglHUvthRMPuoszAIlHRCERzDsEaGkBPKG4/+7L89Mke+oMjWQiEwBROTwlRqIeikC'
'PcrwNQWQiEzBZ0SmTAEkMlPk26ucCkhEpgDCM1OmAqJeeuU5ZUogGt8pPR+JPTJlSiBkShQUZe'
'moclogUVDwOzJTpgYSBUXZiX9rmx4IgkigK8wplwAiKCpnnugvAwQYmNcjMV9NGvEBWspPDF+V'
'veOHoFDqM487qnt3a2uIfHfRyQOXBFJrARR6s+WXs2vgwLFcq355IIKDiCMNMBaW7mtAFo1q1W'
'ElWKtuy2OXm9QtxYmoawGJUL3jcwHpiBNxagGJUL3jcwHpiBNxagGJUL3jcwHpiBNxagGJUL3j'
'cwHpiBNx6gU/2fLWVmm7wQAAAABJRU5ErkJggg==';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Wide Gamut Test',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Wide Gamut Test'),
);
}
}

class MyHomePage extends StatelessWidget {
const MyHomePage({super.key, required this.title});

final String title;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.memory(base64Decode(_displayP3Logo)),
],
),
),
);
}
}
Loading

0 comments on commit ddebe83

Please sign in to comment.