diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index 9aeba8e6e3cbb0de14645a054bc8f3fcea94f6f3..3d0e807585fcdc1e33969c3c51f282bae0ea058e 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -26,12 +26,12 @@ source_set("test_font") { # Picks the libdart implementation based on the Flutter runtime mode. group("libdart") { - deps = [] + public_deps = [] if (flutter_runtime_mode == "profile" || flutter_runtime_mode == "release") { - deps += [ "//third_party/dart/runtime:libdart_precompiled_runtime" ] + public_deps += [ "//third_party/dart/runtime:libdart_precompiled_runtime" ] } else { - deps += [ + public_deps += [ "$flutter_root/lib/snapshot", "//third_party/dart/runtime:libdart_jit", ] @@ -115,7 +115,7 @@ executable("runtime_unittests") { "$flutter_root/common", "$flutter_root/fml", "$flutter_root/lib/snapshot", - "$flutter_root/testing", + "$flutter_root/testing:dart", "//third_party/skia", "//third_party/tonic", ] diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc index 8d53f3b13ea62f460a534e0d52762a4cb56522de..7cae71c36e3fdf7b2954a63af3c5b4048f879664 100644 --- a/runtime/dart_isolate.cc +++ b/runtime/dart_isolate.cc @@ -419,7 +419,7 @@ static bool InvokeMainEntrypoint(Dart_Handle user_entrypoint_function) { } FML_WARN_UNUSED_RESULT -bool DartIsolate::Run(const std::string& entrypoint_name) { +bool DartIsolate::Run(const std::string& entrypoint_name, fml::closure on_run) { TRACE_EVENT0("flutter", "DartIsolate::Run"); if (phase_ != Phase::Ready) { return false; @@ -436,12 +436,17 @@ bool DartIsolate::Run(const std::string& entrypoint_name) { phase_ = Phase::Running; FML_DLOG(INFO) << "New isolate is in the running state."; + + if (on_run) { + on_run(); + } return true; } FML_WARN_UNUSED_RESULT bool DartIsolate::RunFromLibrary(const std::string& library_name, - const std::string& entrypoint_name) { + const std::string& entrypoint_name, + fml::closure on_run) { TRACE_EVENT0("flutter", "DartIsolate::RunFromLibrary"); if (phase_ != Phase::Ready) { return false; @@ -459,6 +464,10 @@ bool DartIsolate::RunFromLibrary(const std::string& library_name, phase_ = Phase::Running; FML_DLOG(INFO) << "New isolate is in the running state."; + + if (on_run) { + on_run(); + } return true; } diff --git a/runtime/dart_isolate.h b/runtime/dart_isolate.h index d720deafed1425be3fa15bace4818975215ef0ec..6b92875e1dc0e51cd7a89162ab0398499a035c52 100644 --- a/runtime/dart_isolate.h +++ b/runtime/dart_isolate.h @@ -74,11 +74,12 @@ class DartIsolate : public UIDartState { bool last_piece = true); FML_WARN_UNUSED_RESULT - bool Run(const std::string& entrypoint); + bool Run(const std::string& entrypoint, fml::closure on_run = nullptr); FML_WARN_UNUSED_RESULT bool RunFromLibrary(const std::string& library_name, - const std::string& entrypoint); + const std::string& entrypoint, + fml::closure on_run = nullptr); FML_WARN_UNUSED_RESULT bool Shutdown(); diff --git a/runtime/dart_isolate_unittests.cc b/runtime/dart_isolate_unittests.cc index 59bd9d61bb1aa064af94ba29a8d5285072fb312c..d35766f58f81f81d2383beb7b0ad5fea8f412e12 100644 --- a/runtime/dart_isolate_unittests.cc +++ b/runtime/dart_isolate_unittests.cc @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "flutter/fml/make_copyable.h" #include "flutter/fml/mapping.h" #include "flutter/fml/paths.h" +#include "flutter/fml/synchronization/waitable_event.h" #include "flutter/fml/thread.h" #include "flutter/runtime/dart_isolate.h" #include "flutter/runtime/dart_vm.h" @@ -23,10 +25,7 @@ namespace testing { using DartIsolateTest = RuntimeTest; TEST_F(DartIsolateTest, RootIsolateCreationAndShutdown) { - Settings settings = {}; - SetSnapshotsAndAssets(settings); - settings.task_observer_add = [](intptr_t, fml::closure) {}; - settings.task_observer_remove = [](intptr_t) {}; + auto settings = CreateSettingsForFixture(); auto vm = DartVM::ForProcess(settings); ASSERT_TRUE(vm); TaskRunners task_runners(CURRENT_TEST_NAME, // @@ -53,9 +52,7 @@ TEST_F(DartIsolateTest, RootIsolateCreationAndShutdown) { } TEST_F(DartIsolateTest, IsolateShutdownCallbackIsInIsolateScope) { - Settings settings = {}; - settings.task_observer_add = [](intptr_t, fml::closure) {}; - settings.task_observer_remove = [](intptr_t) {}; + auto settings = CreateSettingsForFixture(); auto vm = DartVM::ForProcess(settings); ASSERT_TRUE(vm); TaskRunners task_runners(CURRENT_TEST_NAME, // @@ -89,30 +86,48 @@ TEST_F(DartIsolateTest, IsolateShutdownCallbackIsInIsolateScope) { class AutoIsolateShutdown { public: - AutoIsolateShutdown(std::shared_ptr isolate) - : isolate_(std::move(isolate)) {} + AutoIsolateShutdown() = default; + + AutoIsolateShutdown(std::shared_ptr isolate, + fml::RefPtr runner) + : isolate_(std::move(isolate)), runner_(std::move(runner)) {} ~AutoIsolateShutdown() { - if (isolate_) { + if (!IsValid()) { + return; + } + fml::AutoResetWaitableEvent latch; + fml::TaskRunner::RunNowOrPostTask(runner_, [isolate = isolate_, &latch]() { FML_LOG(INFO) << "Shutting down isolate."; - if (!isolate_->Shutdown()) { + if (!isolate->Shutdown()) { FML_LOG(ERROR) << "Could not shutdown isolate."; + FML_CHECK(false); } - } + latch.Signal(); + }); + latch.Wait(); } - bool IsValid() const { return isolate_ != nullptr; } + bool IsValid() const { return isolate_ != nullptr && runner_; } FML_WARN_UNUSED_RESULT bool RunInIsolateScope(std::function closure) { - if (!isolate_) { + if (!IsValid()) { return false; } - tonic::DartIsolateScope scope(isolate_->isolate()); - tonic::DartApiScope api_scope; - if (closure) { - return closure(); - } + + bool result = false; + fml::AutoResetWaitableEvent latch; + fml::TaskRunner::RunNowOrPostTask( + runner_, [this, &result, &latch, closure]() { + tonic::DartIsolateScope scope(isolate_->isolate()); + tonic::DartApiScope api_scope; + if (closure) { + result = closure(); + } + latch.Signal(); + }); + latch.Wait(); return true; } @@ -123,21 +138,20 @@ class AutoIsolateShutdown { private: std::shared_ptr isolate_; + fml::RefPtr runner_; FML_DISALLOW_COPY_AND_ASSIGN(AutoIsolateShutdown); }; -static std::unique_ptr RunDartCodeInIsolate( - fml::RefPtr task_runner, - std::string entrypoint) { - Settings settings = {}; - settings.task_observer_add = [](intptr_t, fml::closure) {}; - settings.task_observer_remove = [](intptr_t) {}; - +static void RunDartCodeInIsolate(std::unique_ptr& result, + const Settings& settings, + fml::RefPtr task_runner, + std::string entrypoint) { + FML_CHECK(task_runner->RunsTasksOnCurrentThread()); auto vm = DartVM::ForProcess(settings); if (!vm) { - return {}; + return; } TaskRunners task_runners(CURRENT_TEST_NAME, // task_runner, // @@ -159,16 +173,16 @@ static std::unique_ptr RunDartCodeInIsolate( ); auto root_isolate = - std::make_unique(weak_isolate.lock()); + std::make_unique(weak_isolate.lock(), task_runner); if (!root_isolate->IsValid()) { FML_LOG(ERROR) << "Could not create isolate."; - return {}; + return; } if (root_isolate->get()->GetPhase() != DartIsolate::Phase::LibrariesSetup) { FML_LOG(ERROR) << "Created isolate is in unexpected phase."; - return {}; + return; } if (!DartVM::IsRunningPrecompiledCode()) { @@ -177,7 +191,7 @@ static std::unique_ptr RunDartCodeInIsolate( if (!fml::IsFile(kernel_file_path)) { FML_LOG(ERROR) << "Could not locate kernel file."; - return {}; + return; } auto kernel_file = fml::OpenFile(kernel_file_path.c_str(), false, @@ -185,61 +199,82 @@ static std::unique_ptr RunDartCodeInIsolate( if (!kernel_file.is_valid()) { FML_LOG(ERROR) << "Kernel file descriptor was invalid."; - return {}; + return; } auto kernel_mapping = std::make_unique(kernel_file); if (kernel_mapping->GetMapping() == nullptr) { FML_LOG(ERROR) << "Could not setup kernel mapping."; - return {}; + return; } if (!root_isolate->get()->PrepareForRunningFromKernel( std::move(kernel_mapping))) { FML_LOG(ERROR) << "Could not prepare to run the isolate from the kernel file."; - return {}; + return; } } else { if (!root_isolate->get()->PrepareForRunningFromPrecompiledCode()) { FML_LOG(ERROR) << "Could not prepare to run the isolate from precompiled code."; - return {}; + return; } } if (root_isolate->get()->GetPhase() != DartIsolate::Phase::Ready) { FML_LOG(ERROR) << "Isolate is in unexpected phase."; - return {}; + return; } - if (!root_isolate->get()->Run(entrypoint)) { + if (!root_isolate->get()->Run(entrypoint, + settings.root_isolate_create_callback)) { FML_LOG(ERROR) << "Could not run the method \"" << entrypoint << "\" in the isolate."; - return {}; + return; } - return root_isolate; + root_isolate->get()->AddIsolateShutdownCallback( + settings.root_isolate_shutdown_callback); + + result = std::move(root_isolate); +} + +static std::unique_ptr RunDartCodeInIsolate( + const Settings& settings, + fml::RefPtr task_runner, + std::string entrypoint) { + std::unique_ptr result; + fml::AutoResetWaitableEvent latch; + fml::TaskRunner::RunNowOrPostTask( + task_runner, fml::MakeCopyable([&]() mutable { + RunDartCodeInIsolate(result, settings, task_runner, entrypoint); + latch.Signal(); + })); + latch.Wait(); + return result; } TEST_F(DartIsolateTest, IsolateCanLoadAndRunDartCode) { - auto isolate = RunDartCodeInIsolate(GetCurrentTaskRunner(), "main"); + auto isolate = RunDartCodeInIsolate(CreateSettingsForFixture(), + GetCurrentTaskRunner(), "main"); ASSERT_TRUE(isolate); ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running); } TEST_F(DartIsolateTest, IsolateCannotLoadAndRunUnknownDartEntrypoint) { - auto isolate = - RunDartCodeInIsolate(GetCurrentTaskRunner(), "thisShouldNotExist"); + auto isolate = RunDartCodeInIsolate( + CreateSettingsForFixture(), GetCurrentTaskRunner(), "thisShouldNotExist"); ASSERT_FALSE(isolate); } TEST_F(DartIsolateTest, CanRunDartCodeCodeSynchronously) { - auto isolate = RunDartCodeInIsolate(GetCurrentTaskRunner(), "main"); + auto isolate = RunDartCodeInIsolate(CreateSettingsForFixture(), + GetCurrentTaskRunner(), "main"); ASSERT_TRUE(isolate); - + ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running); ASSERT_TRUE(isolate->RunInIsolateScope([]() -> bool { if (tonic::LogIfError(::Dart_Invoke(Dart_RootLibrary(), tonic::ToDart("sayHi"), 0, nullptr))) { @@ -249,5 +284,20 @@ TEST_F(DartIsolateTest, CanRunDartCodeCodeSynchronously) { })); } +TEST_F(DartIsolateTest, CanRegisterNativeCallback) { + fml::AutoResetWaitableEvent latch; + AddNativeCallback("NotifyNative", + CREATE_NATIVE_ENTRY(([&latch](Dart_NativeArguments args) { + FML_LOG(ERROR) << "Hello from Dart!"; + latch.Signal(); + }))); + auto isolate = + RunDartCodeInIsolate(CreateSettingsForFixture(), GetThreadTaskRunner(), + "canRegisterNativeCallback"); + ASSERT_TRUE(isolate); + ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running); + latch.Wait(); +} + } // namespace testing } // namespace blink diff --git a/runtime/fixtures/simple_main.dart b/runtime/fixtures/simple_main.dart index 308e033efb1e37567cc17659fc0231df5b07d440..594f69470bc2f10051e8e7ccedbb8e77306f957f 100644 --- a/runtime/fixtures/simple_main.dart +++ b/runtime/fixtures/simple_main.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:isolate'; + void main() { } @@ -14,3 +16,12 @@ void sayHi() { void throwExceptionNow() { throw("Hello"); } + +@pragma('vm:entry-point') +void canRegisterNativeCallback() async { + print("In function canRegisterNativeCallback"); + NotifyNative(); + print("Called native method from canRegisterNativeCallback"); +} + +void NotifyNative() native "NotifyNative"; diff --git a/runtime/runtime_test.cc b/runtime/runtime_test.cc index 002971e8853e04be73931f8581fad60b1087bac7..2613b133d241b08e8ac55bd401ed01beaf46e11e 100644 --- a/runtime/runtime_test.cc +++ b/runtime/runtime_test.cc @@ -10,7 +10,8 @@ namespace blink { namespace testing { -RuntimeTest::RuntimeTest() = default; +RuntimeTest::RuntimeTest() + : native_resolver_(std::make_shared<::testing::TestDartNativeResolver>()) {} RuntimeTest::~RuntimeTest() = default; @@ -70,6 +71,17 @@ void RuntimeTest::SetSnapshotsAndAssets(Settings& settings) { } } +Settings RuntimeTest::CreateSettingsForFixture() { + Settings settings; + settings.task_observer_add = [](intptr_t, fml::closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + settings.root_isolate_create_callback = [this]() { + native_resolver_->SetNativeResolverForIsolate(); + }; + SetSnapshotsAndAssets(settings); + return settings; +} + // |testing::ThreadTest| void RuntimeTest::SetUp() { assets_dir_ = fml::OpenDirectory(::testing::GetFixturesPath(), false, @@ -83,5 +95,10 @@ void RuntimeTest::TearDown() { assets_dir_.reset(); } +void RuntimeTest::AddNativeCallback(std::string name, + Dart_NativeFunction callback) { + native_resolver_->AddNativeCallback(std::move(name), callback); +} + } // namespace testing } // namespace blink diff --git a/runtime/runtime_test.h b/runtime/runtime_test.h index 86dfc5174c44480fb447d325819eca049c97e2e9..142a5d3937d5bee44efa29725397cd2eb843db5c 100644 --- a/runtime/runtime_test.h +++ b/runtime/runtime_test.h @@ -5,8 +5,11 @@ #ifndef FLUTTER_RUNTIME_RUNTIME_TEST_H_ #define FLUTTER_RUNTIME_RUNTIME_TEST_H_ +#include + #include "flutter/common/settings.h" #include "flutter/fml/macros.h" +#include "flutter/testing/test_dart_native_resolver.h" #include "flutter/testing/thread_test.h" namespace blink { @@ -18,7 +21,9 @@ class RuntimeTest : public ::testing::ThreadTest { ~RuntimeTest(); - void SetSnapshotsAndAssets(Settings& settings); + Settings CreateSettingsForFixture(); + + void AddNativeCallback(std::string name, Dart_NativeFunction callback); protected: // |testing::ThreadTest| @@ -29,6 +34,9 @@ class RuntimeTest : public ::testing::ThreadTest { private: fml::UniqueFD assets_dir_; + std::shared_ptr<::testing::TestDartNativeResolver> native_resolver_; + + void SetSnapshotsAndAssets(Settings& settings); }; } // namespace testing diff --git a/shell/platform/embedder/BUILD.gn b/shell/platform/embedder/BUILD.gn index 6b54826cfa132c28b1febe0ca8a66befe97e33d8..b856328855e05df0ae554b669de15ed3a54e1ab1 100644 --- a/shell/platform/embedder/BUILD.gn +++ b/shell/platform/embedder/BUILD.gn @@ -72,8 +72,6 @@ executable("embedder_unittests") { "tests/embedder_context.h", "tests/embedder_test.cc", "tests/embedder_test.h", - "tests/embedder_test_resolver.cc", - "tests/embedder_test_resolver.h", "tests/embedder_unittests.cc", ] @@ -82,7 +80,7 @@ executable("embedder_unittests") { ":fixtures", "$flutter_root/lib/ui", "$flutter_root/runtime", - "$flutter_root/testing", + "$flutter_root/testing:dart", "//third_party/skia", "//third_party/tonic", ] diff --git a/shell/platform/embedder/tests/embedder_a11y_unittests.cc b/shell/platform/embedder/tests/embedder_a11y_unittests.cc index 58728e524f3e61de2a609e3bf183ff1579e1b99c..bfabfd491f13e05c18f9ea8d401ce4ee4d45bb25 100644 --- a/shell/platform/embedder/tests/embedder_a11y_unittests.cc +++ b/shell/platform/embedder/tests/embedder_a11y_unittests.cc @@ -34,7 +34,7 @@ TEST_F(Embedder11yTest, A11yTreeIsConsistent) { }))); // Called by test fixture on UI thread to pass data back to this test. - NativeEntry callback; + ::testing::NativeEntry callback; context.AddNativeCallback( "NotifyTestData", CREATE_NATIVE_ENTRY(([&callback](Dart_NativeArguments args) { diff --git a/shell/platform/embedder/tests/embedder_context.cc b/shell/platform/embedder/tests/embedder_context.cc index 5a21ebeed8b006093a56c35d38fc234921e76178..00faf97413d516f5e34c695f469b75b72e5c1bb3 100644 --- a/shell/platform/embedder/tests/embedder_context.cc +++ b/shell/platform/embedder/tests/embedder_context.cc @@ -37,7 +37,7 @@ static std::unique_ptr GetMapping(const fml::UniqueFD& directory, EmbedderContext::EmbedderContext(std::string assets_path) : assets_path_(std::move(assets_path)), - native_resolver_(std::make_shared()) { + native_resolver_(std::make_shared<::testing::TestDartNativeResolver>()) { auto assets_dir = fml::OpenDirectory(assets_path_.c_str(), false, fml::FilePermission::kRead); vm_snapshot_data_ = GetMapping(assets_dir, "vm_snapshot_data", false); @@ -52,8 +52,8 @@ EmbedderContext::EmbedderContext(std::string assets_path) } isolate_create_callbacks_.push_back( - [weak_resolver = - std::weak_ptr{native_resolver_}]() { + [weak_resolver = std::weak_ptr<::testing::TestDartNativeResolver>{ + native_resolver_}]() { if (auto resolver = weak_resolver.lock()) { resolver->SetNativeResolverForIsolate(); } diff --git a/shell/platform/embedder/tests/embedder_context.h b/shell/platform/embedder/tests/embedder_context.h index 564262a859ef88750222ca280e59cf74a8379b3a..c1b65a38650daf41bd1db8fab98c7d547755cea4 100644 --- a/shell/platform/embedder/tests/embedder_context.h +++ b/shell/platform/embedder/tests/embedder_context.h @@ -14,22 +14,11 @@ #include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" #include "flutter/shell/platform/embedder/embedder.h" -#include "flutter/shell/platform/embedder/tests/embedder_test_resolver.h" - -#define CREATE_NATIVE_ENTRY(native_entry) \ - ([&]() { \ - static ::shell::testing::NativeEntry closure; \ - static Dart_NativeFunction entrypoint = [](Dart_NativeArguments args) { \ - closure(args); \ - }; \ - closure = (native_entry); \ - return entrypoint; \ - })() +#include "flutter/testing/test_dart_native_resolver.h" namespace shell { namespace testing { -using NativeEntry = std::function; using SemanticsNodeCallback = std::function; using SemanticsActionCallback = std::function; @@ -69,7 +58,7 @@ class EmbedderContext { std::unique_ptr isolate_snapshot_data_; std::unique_ptr isolate_snapshot_instructions_; std::vector isolate_create_callbacks_; - std::shared_ptr native_resolver_; + std::shared_ptr<::testing::TestDartNativeResolver> native_resolver_; SemanticsNodeCallback update_semantics_node_callback_; SemanticsActionCallback update_semantics_custom_action_callback_; diff --git a/shell/platform/embedder/tests/embedder_test_resolver.h b/shell/platform/embedder/tests/embedder_test_resolver.h deleted file mode 100644 index 69d08efe1042d0c43ae44127dea62b6dc43ee4fd..0000000000000000000000000000000000000000 --- a/shell/platform/embedder/tests/embedder_test_resolver.h +++ /dev/null @@ -1,47 +0,0 @@ -// 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. - -#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_TESTS_EMBEDDER_TEST_RESOLVER_H_ -#define FLUTTER_SHELL_PLATFORM_EMBEDDER_TESTS_EMBEDDER_TEST_RESOLVER_H_ - -#include -#include - -#include "flutter/fml/macros.h" -#include "third_party/dart/runtime/include/dart_api.h" - -namespace shell { -namespace testing { - -class EmbedderTestResolver - : public std::enable_shared_from_this { - public: - EmbedderTestResolver(); - - ~EmbedderTestResolver(); - - void AddNativeCallback(std::string name, Dart_NativeFunction callback); - - private: - // Friend so that the context can set the native resolver. - friend class EmbedderContext; - - std::map native_callbacks_; - - void SetNativeResolverForIsolate(); - - Dart_NativeFunction ResolveCallback(std::string name) const; - - static Dart_NativeFunction DartNativeEntryResolverCallback( - Dart_Handle dart_name, - int num_of_arguments, - bool* auto_setup_scope); - - FML_DISALLOW_COPY_AND_ASSIGN(EmbedderTestResolver); -}; - -} // namespace testing -} // namespace shell - -#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_TESTS_EMBEDDER_TEST_RESOLVER_H_ diff --git a/testing/BUILD.gn b/testing/BUILD.gn index 424d978f815701ebd367453fb52e30ec1cdf4c0d..54c4cf4aad2e5c4c01952f6ec70cb37cf04a52a6 100644 --- a/testing/BUILD.gn +++ b/testing/BUILD.gn @@ -20,3 +20,18 @@ source_set("testing") { public_configs = [ "$flutter_root:config" ] } + +source_set("dart") { + testonly = true + + sources = [ + "$flutter_root/testing/test_dart_native_resolver.cc", + "$flutter_root/testing/test_dart_native_resolver.h", + ] + + public_deps = [ + ":testing", + "$flutter_root/runtime:libdart", + "//third_party/tonic", + ] +} diff --git a/shell/platform/embedder/tests/embedder_test_resolver.cc b/testing/test_dart_native_resolver.cc similarity index 76% rename from shell/platform/embedder/tests/embedder_test_resolver.cc rename to testing/test_dart_native_resolver.cc index 49171a91df23c95ee8e03dbc584de7e8c959af0a..62fb2a4944d9670ec6a6c1906c6ebc531e146d6e 100644 --- a/shell/platform/embedder/tests/embedder_test_resolver.cc +++ b/testing/test_dart_native_resolver.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/shell/platform/embedder/tests/embedder_test_resolver.h" +#include "flutter/testing/test_dart_native_resolver.h" #include #include @@ -10,19 +10,18 @@ #include "flutter/fml/synchronization/thread_annotations.h" #include "tonic/converter/dart_converter.h" -namespace shell { namespace testing { -EmbedderTestResolver::EmbedderTestResolver() = default; +TestDartNativeResolver::TestDartNativeResolver() = default; -EmbedderTestResolver::~EmbedderTestResolver() = default; +TestDartNativeResolver::~TestDartNativeResolver() = default; -void EmbedderTestResolver::AddNativeCallback(std::string name, - Dart_NativeFunction callback) { +void TestDartNativeResolver::AddNativeCallback(std::string name, + Dart_NativeFunction callback) { native_callbacks_[name] = callback; } -Dart_NativeFunction EmbedderTestResolver::ResolveCallback( +Dart_NativeFunction TestDartNativeResolver::ResolveCallback( std::string name) const { auto found = native_callbacks_.find(name); if (found == native_callbacks_.end()) { @@ -33,10 +32,10 @@ Dart_NativeFunction EmbedderTestResolver::ResolveCallback( } static std::mutex gIsolateResolversMutex; -static std::map> +static std::map> gIsolateResolvers FML_GUARDED_BY(gIsolateResolversMutex); -Dart_NativeFunction EmbedderTestResolver::DartNativeEntryResolverCallback( +Dart_NativeFunction TestDartNativeResolver::DartNativeEntryResolverCallback( Dart_Handle dart_name, int num_of_arguments, bool* auto_setup_scope) { @@ -62,7 +61,7 @@ static const uint8_t* DartNativeEntrySymbolCallback( return reinterpret_cast("¯\\_(ツ)_/¯"); } -void EmbedderTestResolver::SetNativeResolverForIsolate() { +void TestDartNativeResolver::SetNativeResolverForIsolate() { auto result = Dart_SetNativeResolver(Dart_RootLibrary(), DartNativeEntryResolverCallback, DartNativeEntrySymbolCallback); @@ -87,4 +86,3 @@ void EmbedderTestResolver::SetNativeResolverForIsolate() { } } // namespace testing -} // namespace shell diff --git a/testing/test_dart_native_resolver.h b/testing/test_dart_native_resolver.h new file mode 100644 index 0000000000000000000000000000000000000000..8b928170d4f802bc4063eee6ade3a1b4ac8fad9f --- /dev/null +++ b/testing/test_dart_native_resolver.h @@ -0,0 +1,54 @@ +// 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. + +#ifndef FLUTTER_TESTING_TEST_DART_NATIVE_RESOLVER_H_ +#define FLUTTER_TESTING_TEST_DART_NATIVE_RESOLVER_H_ + +#include +#include + +#include "flutter/fml/macros.h" +#include "third_party/dart/runtime/include/dart_api.h" + +#define CREATE_NATIVE_ENTRY(native_entry) \ + ([&]() { \ + static ::testing::NativeEntry closure; \ + static Dart_NativeFunction entrypoint = [](Dart_NativeArguments args) { \ + closure(args); \ + }; \ + closure = (native_entry); \ + return entrypoint; \ + })() + +namespace testing { + +using NativeEntry = std::function; + +class TestDartNativeResolver + : public std::enable_shared_from_this { + public: + TestDartNativeResolver(); + + ~TestDartNativeResolver(); + + void AddNativeCallback(std::string name, Dart_NativeFunction callback); + + void SetNativeResolverForIsolate(); + + private: + std::map native_callbacks_; + + Dart_NativeFunction ResolveCallback(std::string name) const; + + static Dart_NativeFunction DartNativeEntryResolverCallback( + Dart_Handle dart_name, + int num_of_arguments, + bool* auto_setup_scope); + + FML_DISALLOW_COPY_AND_ASSIGN(TestDartNativeResolver); +}; + +} // namespace testing + +#endif // FLUTTER_TESTING_TEST_DART_NATIVE_RESOLVER_H_