Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@
}
// If there were not enough existing clip views, add more.
while (clipIndex < number_of_clips) {
ChildClippingView* clippingView = [ChildClippingView new];
ChildClippingView* clippingView =
[[ChildClippingView alloc] initWithFrame:flutter_view_.get().bounds];
[clippingView addSubview:head];
head = clippingView;
clipIndex++;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.flutter.plugins;

import io.flutter.plugin.common.PluginRegistry;

/**
* Generated file. Do not edit.
*/
public final class GeneratedPluginRegistrant {
public static void registerWith(PluginRegistry registry) {
if (alreadyRegisteredWith(registry)) {
return;
}
}

private static boolean alreadyRegisteredWith(PluginRegistry registry) {
final String key = GeneratedPluginRegistrant.class.getCanonicalName();
if (registry.hasPlugin(key)) {
return true;
}
registry.registrarFor(key);
return false;
}
}
14 changes: 14 additions & 0 deletions testing/scenario_app/ios/Runner/GeneratedPluginRegistrant.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Generated file. Do not edit.
//

#ifndef GeneratedPluginRegistrant_h
#define GeneratedPluginRegistrant_h

#import <Flutter/Flutter.h>

@interface GeneratedPluginRegistrant : NSObject
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry;
@end

#endif /* GeneratedPluginRegistrant_h */
12 changes: 12 additions & 0 deletions testing/scenario_app/ios/Runner/GeneratedPluginRegistrant.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// Generated file. Do not edit.
//

#import "GeneratedPluginRegistrant.h"

@implementation GeneratedPluginRegistrant

+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@
24D47D1B230C79840069DD5E /* golden_platform_view_D211AP.png in Resources */ = {isa = PBXBuildFile; fileRef = 24D47D1A230C79840069DD5E /* golden_platform_view_D211AP.png */; };
24D47D1D230CA2700069DD5E /* golden_platform_view_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 24D47D1C230CA2700069DD5E /* golden_platform_view_iPhone SE_simulator.png */; };
24F1FB89230B4579005ACE7C /* TextPlatformView.m in Sources */ = {isa = PBXBuildFile; fileRef = 24F1FB87230B4579005ACE7C /* TextPlatformView.m */; };
6816DB9E231750ED00A51400 /* GoldenPlatformViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6816DB9D231750ED00A51400 /* GoldenPlatformViewTests.m */; };
6816DBA12317573300A51400 /* GoldenImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 6816DBA02317573300A51400 /* GoldenImage.m */; };
6816DBA42318358200A51400 /* PlatformViewGoldenTestManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6816DBA32318358200A51400 /* PlatformViewGoldenTestManager.m */; };
6816DBAA2318696600A51400 /* golden_platform_view_clippath_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6816DBA52318696600A51400 /* golden_platform_view_clippath_iPhone SE_simulator.png */; };
6816DBAB2318696600A51400 /* golden_platform_view_transform_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6816DBA62318696600A51400 /* golden_platform_view_transform_iPhone SE_simulator.png */; };
6816DBAC2318696600A51400 /* golden_platform_view_opacity_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6816DBA72318696600A51400 /* golden_platform_view_opacity_iPhone SE_simulator.png */; };
6816DBAD2318696600A51400 /* golden_platform_view_cliprect_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6816DBA82318696600A51400 /* golden_platform_view_cliprect_iPhone SE_simulator.png */; };
6816DBAE2318696600A51400 /* golden_platform_view_cliprrect_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6816DBA92318696600A51400 /* golden_platform_view_cliprrect_iPhone SE_simulator.png */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -113,6 +121,17 @@
24D47D1E230CA4480069DD5E /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
24F1FB87230B4579005ACE7C /* TextPlatformView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TextPlatformView.m; sourceTree = "<group>"; };
24F1FB88230B4579005ACE7C /* TextPlatformView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextPlatformView.h; sourceTree = "<group>"; };
6816DB9C231750ED00A51400 /* GoldenPlatformViewTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GoldenPlatformViewTests.h; sourceTree = "<group>"; };
6816DB9D231750ED00A51400 /* GoldenPlatformViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoldenPlatformViewTests.m; sourceTree = "<group>"; };
6816DB9F2317573300A51400 /* GoldenImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GoldenImage.h; sourceTree = "<group>"; };
6816DBA02317573300A51400 /* GoldenImage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoldenImage.m; sourceTree = "<group>"; };
6816DBA22318358200A51400 /* PlatformViewGoldenTestManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlatformViewGoldenTestManager.h; sourceTree = "<group>"; };
6816DBA32318358200A51400 /* PlatformViewGoldenTestManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PlatformViewGoldenTestManager.m; sourceTree = "<group>"; };
6816DBA52318696600A51400 /* golden_platform_view_clippath_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_clippath_iPhone SE_simulator.png"; sourceTree = "<group>"; };
6816DBA62318696600A51400 /* golden_platform_view_transform_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_transform_iPhone SE_simulator.png"; sourceTree = "<group>"; };
6816DBA72318696600A51400 /* golden_platform_view_opacity_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_opacity_iPhone SE_simulator.png"; sourceTree = "<group>"; };
6816DBA82318696600A51400 /* golden_platform_view_cliprect_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_cliprect_iPhone SE_simulator.png"; sourceTree = "<group>"; };
6816DBA92318696600A51400 /* golden_platform_view_cliprrect_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_cliprrect_iPhone SE_simulator.png"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -200,9 +219,20 @@
244EA6CF230DBE8900B2D26E /* golden_platform_view_D21AP.png */,
24D47D1C230CA2700069DD5E /* golden_platform_view_iPhone SE_simulator.png */,
24D47D1A230C79840069DD5E /* golden_platform_view_D211AP.png */,
6816DBA52318696600A51400 /* golden_platform_view_clippath_iPhone SE_simulator.png */,
6816DBA82318696600A51400 /* golden_platform_view_cliprect_iPhone SE_simulator.png */,
6816DBA92318696600A51400 /* golden_platform_view_cliprrect_iPhone SE_simulator.png */,
6816DBA72318696600A51400 /* golden_platform_view_opacity_iPhone SE_simulator.png */,
6816DBA62318696600A51400 /* golden_platform_view_transform_iPhone SE_simulator.png */,
248D76EE22E388380012F0C1 /* PlatformViewUITests.m */,
248D76F022E388380012F0C1 /* Info.plist */,
24D47D1E230CA4480069DD5E /* README.md */,
6816DB9C231750ED00A51400 /* GoldenPlatformViewTests.h */,
6816DB9D231750ED00A51400 /* GoldenPlatformViewTests.m */,
6816DB9F2317573300A51400 /* GoldenImage.h */,
6816DBA02317573300A51400 /* GoldenImage.m */,
6816DBA22318358200A51400 /* PlatformViewGoldenTestManager.h */,
6816DBA32318358200A51400 /* PlatformViewGoldenTestManager.m */,
);
path = ScenariosUITests;
sourceTree = "<group>";
Expand Down Expand Up @@ -340,9 +370,14 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6816DBAE2318696600A51400 /* golden_platform_view_cliprrect_iPhone SE_simulator.png in Resources */,
6816DBAB2318696600A51400 /* golden_platform_view_transform_iPhone SE_simulator.png in Resources */,
6816DBAA2318696600A51400 /* golden_platform_view_clippath_iPhone SE_simulator.png in Resources */,
6816DBAD2318696600A51400 /* golden_platform_view_cliprect_iPhone SE_simulator.png in Resources */,
24D47D1B230C79840069DD5E /* golden_platform_view_D211AP.png in Resources */,
24D47D1D230CA2700069DD5E /* golden_platform_view_iPhone SE_simulator.png in Resources */,
244EA6D0230DBE8900B2D26E /* golden_platform_view_D21AP.png in Resources */,
6816DBAC2318696600A51400 /* golden_platform_view_opacity_iPhone SE_simulator.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -375,6 +410,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6816DBA12317573300A51400 /* GoldenImage.m in Sources */,
6816DB9E231750ED00A51400 /* GoldenPlatformViewTests.m in Sources */,
6816DBA42318358200A51400 /* PlatformViewGoldenTestManager.m in Sources */,
248D76EF22E388380012F0C1 /* PlatformViewUITests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
56 changes: 42 additions & 14 deletions testing/scenario_app/ios/Scenarios/Scenarios/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,55 @@ - (BOOL)application:(UIApplication*)application

// This argument is used by the XCUITest for Platform Views so that the app
// under test will create platform views.
if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--platform-view"]) {
FlutterEngine* engine = [[FlutterEngine alloc] initWithScenario:@"text_platform_view"
withCompletion:nil];
[engine runWithEntrypoint:nil];

FlutterViewController* flutterViewController =
[[NoStatusBarFlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
TextPlatformViewFactory* textPlatformViewFactory =
[[TextPlatformViewFactory alloc] initWithMessenger:flutterViewController.binaryMessenger];
NSObject<FlutterPluginRegistrar>* registrar =
[flutterViewController.engine registrarForPlugin:@"scenarios/TextPlatformViewPlugin"];
[registrar registerViewFactory:textPlatformViewFactory withId:@"scenarios/textPlatformView"];
self.window.rootViewController = flutterViewController;
// The launchArgsMap should match the one in the `PlatformVieGoldenTestManager`.
NSDictionary<NSString*, NSString*>* launchArgsMap = @{
@"--platform-view" : @"platform_view",
@"--platform-view-cliprect" : @"platform_view_cliprect",
@"--platform-view-cliprrect" : @"platform_view_cliprrect",
@"--platform-view-clippath" : @"platform_view_clippath",
@"--platform-view-transform" : @"platform_view_transform",
@"--platform-view-opacity" : @"platform_view_opacity",
};
__block NSString* goldenTestName = nil;
[launchArgsMap
enumerateKeysAndObjectsUsingBlock:^(NSString* argument, NSString* testName, BOOL* stop) {
if ([[[NSProcessInfo processInfo] arguments] containsObject:argument]) {
goldenTestName = testName;
*stop = YES;
}
}];

if (goldenTestName) {
[self readyContextForPlatformViewTests:goldenTestName];
} else if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--screen-before-flutter"]) {
self.window.rootViewController = [[ScreenBeforeFlutter alloc] initWithEngineRunCompletion:nil];
} else {
self.window.rootViewController = [[UIViewController alloc] init];
}
[self.window makeKeyAndVisible];

[self.window makeKeyAndVisible];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (void)readyContextForPlatformViewTests:(NSString*)scenarioIdentifier {
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"PlatformViewTest" project:nil];
[engine runWithEntrypoint:nil];

FlutterViewController* flutterViewController =
[[NoStatusBarFlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
[engine.binaryMessenger
setMessageHandlerOnChannel:@"scenario_status"
binaryMessageHandler:^(NSData* _Nullable message, FlutterBinaryReply _Nonnull reply) {
[engine.binaryMessenger
sendOnChannel:@"set_scenario"
message:[scenarioIdentifier dataUsingEncoding:NSUTF8StringEncoding]];
}];
TextPlatformViewFactory* textPlatformViewFactory =
[[TextPlatformViewFactory alloc] initWithMessenger:flutterViewController.binaryMessenger];
NSObject<FlutterPluginRegistrar>* registrar =
[flutterViewController.engine registrarForPlugin:@"scenarios/TextPlatformViewPlugin"];
[registrar registerViewFactory:textPlatformViewFactory withId:@"scenarios/textPlatformView"];
self.window.rootViewController = flutterViewController;
}

@end
26 changes: 26 additions & 0 deletions testing/scenario_app/ios/Scenarios/ScenariosUITests/GoldenImage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2013 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 <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface GoldenImage : NSObject

@property(readonly, copy, nonatomic) NSString* goldenName;
@property(readonly, strong, nonatomic) UIImage* image;

// Initilize with the golden file's prefix.
//
// Create an image from a golden file named prefix+devicemodel.
- (instancetype)initWithGoldenNamePrefix:(NSString*)prefix;

// Compare this GoldenImage to `image`.
//
// Return YES if the `image` of this GoldenImage have the same pixels of provided `image`.
- (BOOL)compareGoldenToImage:(UIImage*)image;

@end

NS_ASSUME_NONNULL_END
94 changes: 94 additions & 0 deletions testing/scenario_app/ios/Scenarios/ScenariosUITests/GoldenImage.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright 2013 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 "GoldenImage.h"
#import <XCTest/XCTest.h>
#include <sys/sysctl.h>

@interface GoldenImage ()

@end

@implementation GoldenImage

- (instancetype)initWithGoldenNamePrefix:(NSString*)prefix {
self = [super init];
if (self) {
_goldenName = [prefix stringByAppendingString:_platformName()];
NSBundle* bundle = [NSBundle bundleForClass:[self class]];
NSURL* goldenURL = [bundle URLForResource:_goldenName withExtension:@"png"];
NSData* data = [NSData dataWithContentsOfURL:goldenURL];
_image = [[UIImage alloc] initWithData:data];
}
return self;
}

- (BOOL)compareGoldenToImage:(UIImage*)image {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Override -isEqual: and -hash instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Override -isEqual: and -hash instead.

Oh actually never mind, that would require you to make a GoldenImage out of the screen shot. This is fine.

if (!self.image || !image) {
return NO;
}
CGImageRef imageRefA = [self.image CGImage];
CGImageRef imageRefB = [image CGImage];

NSUInteger widthA = CGImageGetWidth(imageRefA);
NSUInteger heightA = CGImageGetHeight(imageRefA);
NSUInteger widthB = CGImageGetWidth(imageRefB);
NSUInteger heightB = CGImageGetHeight(imageRefB);

if (widthA != widthB || heightA != heightB) {
return NO;
}
NSUInteger bytesPerPixel = 4;
NSUInteger size = widthA * heightA * bytesPerPixel;
NSMutableData* rawA = [NSMutableData dataWithLength:size];
NSMutableData* rawB = [NSMutableData dataWithLength:size];

if (!rawA || !rawB) {
return NO;
}

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

NSUInteger bytesPerRow = bytesPerPixel * widthA;
NSUInteger bitsPerComponent = 8;
CGContextRef contextA =
CGBitmapContextCreate(rawA.mutableBytes, widthA, heightA, bitsPerComponent, bytesPerRow,
colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

CGContextDrawImage(contextA, CGRectMake(0, 0, widthA, heightA), imageRefA);
CGContextRelease(contextA);

CGContextRef contextB =
CGBitmapContextCreate(rawB.mutableBytes, widthA, heightA, bitsPerComponent, bytesPerRow,
colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);

CGContextDrawImage(contextB, CGRectMake(0, 0, widthA, heightA), imageRefB);
CGContextRelease(contextB);

if (memcmp(rawA.mutableBytes, rawB.mutableBytes, size)) {
return NO;
}

return YES;
}

NS_INLINE NSString* _platformName() {
NSString* simulatorName =
[[NSProcessInfo processInfo].environment objectForKey:@"SIMULATOR_DEVICE_NAME"];
if (simulatorName) {
return [NSString stringWithFormat:@"%@_simulator", simulatorName];
}

size_t size;
sysctlbyname("hw.model", NULL, &size, NULL, 0);
char* answer = malloc(size);
sysctlbyname("hw.model", answer, &size, NULL, 0);

NSString* results = [NSString stringWithCString:answer encoding:NSUTF8StringEncoding];
free(answer);
return results;
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2013 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 <XCTest/XCTest.h>
#import "PlatformViewGoldenTestManager.h"

NS_ASSUME_NONNULL_BEGIN

// The base class of all the PlatformView golden tests.
//
// A new PlatformView golden tests can subclass this and override the `-initiWithInvocation:`
// method, which then retun the `-initWithManager:invocation:`
//
// Then in any test method, call `checkGolden` to perform the golden test.
//
// This base class doesn't run any test case on its own.
@interface GoldenPlatformViewTests : XCTestCase

// Initialize with a `PlatformViewGoldenTestManager`.
- (instancetype)initWithManager:(PlatformViewGoldenTestManager*)manager
invocation:(NSInvocation*)invocation;

// Take a sceenshot of the test app and check it has the same pixels with goldenImage inside the
// `PlatformViewGoldenTestManager`.
- (void)checkGolden;

@end

NS_ASSUME_NONNULL_END
Loading