Add support for native callbacks to the macOS embedder test harness (flutter/engine#26623)

This commit is contained in:
George Wright 2021-06-09 17:28:13 -07:00 committed by GitHub
parent 8c094f2c8a
commit a877ccf4ee
9 changed files with 142 additions and 29 deletions

View File

@ -1160,6 +1160,9 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEmbed
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponderUnittests.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTestContext.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.mm

View File

@ -176,6 +176,8 @@ executable("flutter_desktop_darwin_unittests") {
"framework/Source/FlutterEmbedderExternalTextureUnittests.mm",
"framework/Source/FlutterEmbedderKeyResponderUnittests.mm",
"framework/Source/FlutterEngineTest.mm",
"framework/Source/FlutterEngineTestUtils.h",
"framework/Source/FlutterEngineTestUtils.mm",
"framework/Source/FlutterGLCompositorUnittests.mm",
"framework/Source/FlutterKeyboardManagerUnittests.mm",
"framework/Source/FlutterMetalCompositorUnittests.mm",

View File

@ -30,6 +30,11 @@
*/
@property(nonatomic, readonly) std::vector<std::string> switches;
/**
* The callback invoked by the engine in root isolate scope.
*/
@property(nonatomic, nullable) void (*rootIsolateCreateCallback)(void* _Nullable);
/**
* Instead of looking up the assets and ICU data path in the application bundle, this initializer
* allows callers to create a Dart project with custom locations specified for the both.

View File

@ -235,6 +235,7 @@ static void OnPlatformMessage(const FlutterPlatformMessage* message, FlutterEngi
flutterArguments.shutdown_dart_vm_when_done = true;
flutterArguments.dart_entrypoint_argc = dartEntrypointArgs.size();
flutterArguments.dart_entrypoint_argv = dartEntrypointArgs.data();
flutterArguments.root_isolate_create_callback = _project.rootIsolateCreateCallback;
static size_t sTaskRunnerIdentifiers = 0;
const FlutterTaskRunnerDescription cocoa_task_runner_description = {

View File

@ -6,12 +6,12 @@
#include "flutter/shell/platform/common/accessibility_bridge.h"
#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppDelegate.h"
#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
#include "flutter/testing/testing.h"
#include "flutter/testing/test_dart_native_resolver.h"
@interface FlutterEngine (Test)
/**
@ -25,26 +25,14 @@
namespace flutter::testing {
namespace {
// Returns an engine configured for the test fixture resource configuration.
FlutterEngine* CreateTestEngine() {
NSString* fixtures = @(testing::GetFixturesPath());
FlutterDartProject* project = [[FlutterDartProject alloc]
initWithAssetsPath:fixtures
ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
return [[FlutterEngine alloc] initWithName:@"test" project:project allowHeadlessExecution:true];
}
} // namespace
TEST(FlutterEngine, CanLaunch) {
FlutterEngine* engine = CreateTestEngine();
TEST_F(FlutterEngineTest, CanLaunch) {
FlutterEngine* engine = GetFlutterEngine();
EXPECT_TRUE([engine runWithEntrypoint:@"main"]);
EXPECT_TRUE(engine.running);
[engine shutDownEngine];
}
TEST(FlutterEngine, MessengerSend) {
FlutterEngine* engine = CreateTestEngine();
TEST_F(FlutterEngineTest, MessengerSend) {
FlutterEngine* engine = GetFlutterEngine();
EXPECT_TRUE([engine runWithEntrypoint:@"main"]);
NSData* test_message = [@"a message" dataUsingEncoding:NSUTF8StringEncoding];
@ -60,12 +48,10 @@ TEST(FlutterEngine, MessengerSend) {
[engine.binaryMessenger sendOnChannel:@"test" message:test_message];
EXPECT_TRUE(called);
[engine shutDownEngine];
}
TEST(FlutterEngine, CanToggleAccessibility) {
FlutterEngine* engine = CreateTestEngine();
TEST_F(FlutterEngineTest, CanToggleAccessibility) {
FlutterEngine* engine = GetFlutterEngine();
// Capture the update callbacks before the embedder API initializes.
auto original_init = engine.embedderAPI.Initialize;
std::function<void(const FlutterSemanticsNode*, void*)> update_node_callback;
@ -162,11 +148,10 @@ TEST(FlutterEngine, CanToggleAccessibility) {
EXPECT_EQ([engine.viewController.flutterView.accessibilityChildren count], 0u);
[engine setViewController:nil];
[engine shutDownEngine];
}
TEST(FlutterEngine, CanToggleAccessibilityWhenHeadless) {
FlutterEngine* engine = CreateTestEngine();
TEST_F(FlutterEngineTest, CanToggleAccessibilityWhenHeadless) {
FlutterEngine* engine = GetFlutterEngine();
// Capture the update callbacks before the embedder API initializes.
auto original_init = engine.embedderAPI.Initialize;
std::function<void(const FlutterSemanticsNode*, void*)> update_node_callback;
@ -245,11 +230,10 @@ TEST(FlutterEngine, CanToggleAccessibilityWhenHeadless) {
EXPECT_FALSE(semanticsEnabled);
// Still no crashes
EXPECT_EQ(engine.viewController, nil);
[engine shutDownEngine];
}
TEST(FlutterEngine, ResetsAccessibilityBridgeWhenSetsNewViewController) {
FlutterEngine* engine = CreateTestEngine();
TEST_F(FlutterEngineTest, ResetsAccessibilityBridgeWhenSetsNewViewController) {
FlutterEngine* engine = GetFlutterEngine();
// Capture the update callbacks before the embedder API initializes.
auto original_init = engine.embedderAPI.Initialize;
std::function<void(const FlutterSemanticsNode*, void*)> update_node_callback;
@ -336,7 +320,22 @@ TEST(FlutterEngine, ResetsAccessibilityBridgeWhenSetsNewViewController) {
EXPECT_TRUE(native_root.expired());
[engine setViewController:nil];
[engine shutDownEngine];
}
TEST_F(FlutterEngineTest, NativeCallbacks) {
FlutterEngine* engine = GetFlutterEngine();
EXPECT_TRUE([engine runWithEntrypoint:@"native_callback"]);
EXPECT_TRUE(engine.running);
fml::AutoResetWaitableEvent latch;
bool latch_called = false;
AddNativeCallback("SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
latch_called = true;
latch.Signal();
}));
latch.Wait();
ASSERT_TRUE(latch_called);
}
TEST(FlutterEngine, Compositor) {

View File

@ -0,0 +1,21 @@
// 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 "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTestContext.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
#include "flutter/testing/testing.h"
namespace flutter::testing {
class FlutterEngineTestContext {
public:
FlutterEngineTestContext(std::string assets_path = "");
virtual ~FlutterEngineTestContext();
private:
static IsolateCreateCallback();
};
} // namespace flutter::testing

View File

@ -0,0 +1,34 @@
// 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 "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h"
#include "flutter/testing/test_dart_native_resolver.h"
#include "gtest/gtest.h"
namespace flutter::testing {
class FlutterEngineTest : public ::testing::Test {
public:
FlutterEngineTest();
FlutterEngine* GetFlutterEngine() { return engine_; };
void SetUp() override;
void TearDown() override;
void AddNativeCallback(const char* name, Dart_NativeFunction function);
static void IsolateCreateCallback(void* user_data);
private:
inline static std::shared_ptr<TestDartNativeResolver> native_resolver_;
FlutterDartProject* project_;
FlutterEngine* engine_;
FML_DISALLOW_COPY_AND_ASSIGN(FlutterEngineTest);
};
} // namespace flutter::testing

View File

@ -0,0 +1,41 @@
// 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 "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
#include "flutter/testing/testing.h"
namespace flutter::testing {
FlutterEngineTest::FlutterEngineTest() = default;
void FlutterEngineTest::SetUp() {
native_resolver_ = std::make_shared<TestDartNativeResolver>();
NSString* fixtures = @(testing::GetFixturesPath());
project_ = [[FlutterDartProject alloc]
initWithAssetsPath:fixtures
ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
project_.rootIsolateCreateCallback = FlutterEngineTest::IsolateCreateCallback;
engine_ = [[FlutterEngine alloc] initWithName:@"test"
project:project_
allowHeadlessExecution:true];
}
void FlutterEngineTest::TearDown() {
[engine_ shutDownEngine];
engine_ = nil;
native_resolver_.reset();
}
void FlutterEngineTest::IsolateCreateCallback(void* user_data) {
native_resolver_->SetNativeResolverForIsolate();
}
void FlutterEngineTest::AddNativeCallback(const char* name, Dart_NativeFunction function) {
native_resolver_->AddNativeCallback({name}, function);
}
} // namespace flutter::testing

View File

@ -28,3 +28,10 @@ void can_composite_platform_views() {
};
PlatformDispatcher.instance.scheduleFrame();
}
void signalNativeTest() native 'SignalNativeTest';
@pragma('vm:entry-point')
void native_callback() {
signalNativeTest();
}