Skip to content
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
20 changes: 20 additions & 0 deletions .ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,26 @@ targets:
- bin/**
- .ci.yaml

- name: Linux plugin_test_linux
recipe: devicelab/devicelab_drone
bringup: true # New task
timeout: 60
properties:
dependencies: >-
[
{"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"},
{"dependency": "cmake", "version": "version:3.16.1"},
{"dependency": "ninja", "version": "version:1.9.0"}
]
tags: >
["devicelab", "hostonly", "linux"]
task_name: plugin_test_linux
runIf:
- dev/**
- packages/flutter_tools/**
- bin/**
- .ci.yaml

- name: Linux run_debug_test_linux
recipe: devicelab/devicelab_drone
bringup: true
Expand Down
1 change: 1 addition & 0 deletions TESTOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@
/dev/devicelab/bin/tasks/platform_view_win_desktop__start_up.dart @yaakovschectman @flutter/desktop
/dev/devicelab/bin/tasks/plugin_lint_mac.dart @stuartmorgan @flutter/plugin
/dev/devicelab/bin/tasks/plugin_test_ios.dart @jmagman @flutter/ios
/dev/devicelab/bin/tasks/plugin_test_linux.dart @stuartmorgan @flutter/desktop
/dev/devicelab/bin/tasks/plugin_test_macos.dart @jmagman @flutter/desktop
/dev/devicelab/bin/tasks/plugin_test_windows.dart @stuartmorgan @flutter/desktop
/dev/devicelab/bin/tasks/plugin_test.dart @stuartmorgan @flutter/plugin
Expand Down
16 changes: 16 additions & 0 deletions dev/devicelab/bin/tasks/plugin_test_linux.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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/framework.dart';
import 'package:flutter_devicelab/tasks/plugin_tests.dart';

Future<void> main() async {
await task(combine(<TaskFunction>[
PluginTest('linux', <String>['--platforms=linux']).call,
// Test that Dart-only plugins are supported.
PluginTest('linux', <String>['--platforms=linux'], dartOnlyPlugin: true).call,
// Test that FFI plugins are supported.
PluginTest('linux', <String>['--platforms=linux'], template: 'plugin_ffi').call,
]));
}
9 changes: 9 additions & 0 deletions dev/devicelab/lib/tasks/plugin_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,15 @@ public class $pluginClass: NSObject, FlutterPlugin {
}
});
break;
case 'linux':
if (await exec(
path.join(rootPath, 'build', 'linux', 'x64', 'release', 'plugins', 'plugintest', 'plugintest_plugin_test'),
<String>[],
canFail: true,
) != 0) {
throw TaskResult.failure('Platform unit tests failed');
}
break;
case 'macos':
if (!await runXcodeTests(
platformDirectory: path.join(rootPath, 'macos'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ set_target_properties(${BINARY_NAME}
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
)

{{#withPlatformChannelPluginHook}}
# Enable the test target.
set(include_{{pluginProjectName}}_tests TRUE)
{{/withPlatformChannelPluginHook}}

# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ project(${PROJECT_NAME} LANGUAGES CXX)
# not be changed.
set(PLUGIN_NAME "{{projectName}}_plugin")

# Any new source files that you add to the plugin should be added here.
list(APPEND PLUGIN_SOURCES
"{{pluginClassSnakeCase}}.cc"
)

# Define the plugin library target. Its name must not be changed (see comment
# on PLUGIN_NAME above).
#
# Any new source files that you add to the plugin should be added here.
add_library(${PLUGIN_NAME} SHARED
"{{pluginClassSnakeCase}}.cc"
${PLUGIN_SOURCES}
)

# Apply a standard set of build settings that are configured in the
Expand Down Expand Up @@ -45,3 +48,47 @@ set({{projectName}}_bundled_libraries
""
PARENT_SCOPE
)

# === Tests ===
# These unit tests can be run from a terminal after building the example.

# Only enable test builds when building the example (which sets this variable)
# so that plugin clients aren't building the tests.
if (${include_${PROJECT_NAME}_tests})
if(${CMAKE_VERSION} VERSION_LESS "3.11.0")
message("Unit tests require CMake 3.11.0 or later")
else()
set(TEST_RUNNER "${PROJECT_NAME}_test")
enable_testing()

# Add the Google Test dependency.
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/release-1.11.0.zip
)
# Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Disable install commands for gtest so it doesn't end up in the bundle.
set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE)

FetchContent_MakeAvailable(googletest)

# The plugin's exported API is not very useful for unit testing, so build the
# sources directly into the test binary rather than using the shared library.
add_executable(${TEST_RUNNER}
test/{{pluginClassSnakeCase}}_test.cc
${PLUGIN_SOURCES}
)
apply_standard_settings(${TEST_RUNNER})
target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
target_link_libraries(${TEST_RUNNER} PRIVATE flutter)
target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::GTK)
target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock)

# Enable automatic test discovery.
include(GoogleTest)
gtest_discover_tests(${TEST_RUNNER})

endif() # CMake version check
endif() # include_${PROJECT_NAME}_tests
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include <cstring>

#include "{{pluginClassSnakeCase}}_private.h"

#define {{pluginClassCapitalSnakeCase}}(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), {{pluginClassSnakeCase}}_get_type(), \
{{pluginClass}}))
Expand All @@ -25,18 +27,22 @@ static void {{pluginClassSnakeCase}}_handle_method_call(
const gchar* method = fl_method_call_get_name(method_call);

if (strcmp(method, "getPlatformVersion") == 0) {
struct utsname uname_data = {};
uname(&uname_data);
g_autofree gchar *version = g_strdup_printf("Linux %s", uname_data.version);
g_autoptr(FlValue) result = fl_value_new_string(version);
response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
response = get_platform_version();
} else {
response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
}

fl_method_call_respond(method_call, response, nullptr);
}

FlMethodResponse* get_platform_version() {
struct utsname uname_data = {};
uname(&uname_data);
g_autofree gchar *version = g_strdup_printf("Linux %s", uname_data.version);
g_autoptr(FlValue) result = fl_value_new_string(version);
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
}

static void {{pluginClassSnakeCase}}_dispose(GObject* object) {
G_OBJECT_CLASS({{pluginClassSnakeCase}}_parent_class)->dispose(object);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <flutter_linux/flutter_linux.h>

#include "include/{{projectName}}/{{pluginClassSnakeCase}}.h"

// This file exposes some plugin internals for unit testing. See
// https://github.com/flutter/flutter/issues/88724 for current limitations
// in the unit-testable API.

// Handles the getPlatformVersion method call.
FlMethodResponse *get_platform_version();
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <flutter_linux/flutter_linux.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "include/{{projectName}}/{{pluginClassSnakeCase}}.h"
#include "{{pluginClassSnakeCase}}_private.h"

// This demonstrates a simple unit test of the C portion of this plugin's
// implementation.
//
// Once you have built the plugin's example app, you can run these tests
// from the command line. For instance, for a plugin called my_plugin
// built for x64 debug, run:
// $ build/linux/x64/debug/plugins/my_plugin/my_plugin_test

namespace {{projectName}} {
namespace test {

TEST({{pluginClass}}, GetPlatformVersion) {
g_autoptr(FlMethodResponse) response = get_platform_version();
ASSERT_NE(response, nullptr);
ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
FlValue* result = fl_method_success_response_get_result(
FL_METHOD_SUCCESS_RESPONSE(response));
ASSERT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_STRING);
// The full string varies, so just valiate that it has the right format.
EXPECT_THAT(fl_value_get_string(result), testing::StartsWith("Linux "));
}

} // namespace test
} // namespace {{projectName}}
2 changes: 2 additions & 0 deletions packages/flutter_tools/templates/template_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@
"templates/plugin/linux.tmpl/CMakeLists.txt.tmpl",
"templates/plugin/linux.tmpl/include/projectName.tmpl/pluginClassSnakeCase.h.tmpl",
"templates/plugin/linux.tmpl/pluginClassSnakeCase.cc.tmpl",
"templates/plugin/linux.tmpl/pluginClassSnakeCase_private.h.tmpl",
"templates/plugin/linux.tmpl/test/pluginClassSnakeCase_test.cc.tmpl",
"templates/plugin/macos.tmpl/Classes/pluginClass.swift.tmpl",
"templates/plugin/README.md.tmpl",
"templates/plugin/test/projectName_test.dart.tmpl",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2555,6 +2555,28 @@ void main() {
Logger: () => logger,
});

testUsingContext('plugin includes native Linux unit tests', () async {
Cache.flutterRoot = '../..';

final CreateCommand command = CreateCommand();
final CommandRunner<void> runner = createTestCommandRunner(command);

await runner.run(<String>[
'create',
'--no-pub',
'--template=plugin',
'--platforms=linux',
projectDir.path]);

expect(projectDir
.childDirectory('linux')
.childDirectory('test')
.childFile('flutter_project_plugin_test.cc'), exists);
}, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
Logger: () => logger,
});

testUsingContext('create a module with --platforms throws error.', () async {
Cache.flutterRoot = '../..';

Expand Down