| Flutter Linux Embedder |

fl_view_test.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h"
6 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
7 #include "flutter/shell/platform/linux/fl_engine_private.h"
8 #include "flutter/shell/platform/linux/fl_view_private.h"
9 #include "flutter/shell/platform/linux/testing/fl_test.h"
10 #include "flutter/shell/platform/linux/testing/fl_test_gtk_logs.h"
11 #include "flutter/shell/platform/linux/testing/mock_gtk.h"
12
13 #include "gtest/gtest.h"
14
15 static void first_frame_cb(FlView* view, gboolean* first_frame_emitted) {
16 *first_frame_emitted = TRUE;
17 }
18
19 TEST(FlViewTest, GetEngine) {
20 flutter::testing::fl_ensure_gtk_init();
21 g_autoptr(FlDartProject) project = fl_dart_project_new();
22 FlView* view = fl_view_new(project);
23
24 // Check the engine is immediately available (i.e. before the widget is
25 // realized).
26 FlEngine* engine = fl_view_get_engine(view);
27 EXPECT_NE(engine, nullptr);
28 }
29
30 TEST(FlViewTest, StateUpdateDoesNotHappenInInit) {
31 flutter::testing::fl_ensure_gtk_init();
32 g_autoptr(FlDartProject) project = fl_dart_project_new();
33 FlView* view = fl_view_new(project);
34 // Check that creating a view doesn't try to query the window state in
35 // initialization, causing a critical log to be issued.
36 EXPECT_EQ(
37 flutter::testing::fl_get_received_gtk_log_levels() & G_LOG_LEVEL_CRITICAL,
38 (GLogLevelFlags)0x0);
39
40 (void)view;
41 }
42
43 TEST(FlViewTest, FirstFrameSignal) {
44 flutter::testing::fl_ensure_gtk_init();
45
46 g_autoptr(FlDartProject) project = fl_dart_project_new();
47 FlView* view = fl_view_new(project);
48 gboolean first_frame_emitted = FALSE;
49 g_signal_connect(view, "first-frame", G_CALLBACK(first_frame_cb),
50 &first_frame_emitted);
51
52 EXPECT_FALSE(first_frame_emitted);
53
54 fl_renderable_redraw(FL_RENDERABLE(view));
55
56 // Signal is emitted in idle, clear the main loop.
57 while (g_main_context_iteration(g_main_context_default(), FALSE)) {
58 // Repeat until nothing to iterate on.
59 }
60
61 // Check view has detected frame.
62 EXPECT_TRUE(first_frame_emitted);
63 }
64
65 // Check semantics update applied
66 TEST(FlViewTest, SemanticsUpdate) {
67 flutter::testing::fl_ensure_gtk_init();
68
69 g_autoptr(FlDartProject) project = fl_dart_project_new();
70 FlView* view = fl_view_new(project);
71
72 FlEngine* engine = fl_view_get_engine(view);
73 g_autoptr(GError) error = nullptr;
74 EXPECT_TRUE(fl_engine_start(engine, &error));
75
76 FlutterSemanticsNode2 root_node = {
77 .id = 0,
78 .label = "root",
79 };
80 FlutterSemanticsNode2* nodes[1] = {&root_node};
81 FlutterSemanticsUpdate2 update = {
82 .node_count = 1, .nodes = nodes, .view_id = 0};
83 g_signal_emit_by_name(engine, "update-semantics", &update);
84
85 FlViewAccessible* accessible = fl_view_get_accessible(view);
86 EXPECT_EQ(atk_object_get_n_accessible_children(ATK_OBJECT(accessible)), 1);
87 AtkObject* root_object =
88 atk_object_ref_accessible_child(ATK_OBJECT(accessible), 0);
89 EXPECT_STREQ(atk_object_get_name(root_object), "root");
90 }
91
92 // Check semantics update ignored for other view
93 TEST(FlViewTest, SemanticsUpdateOtherView) {
94 flutter::testing::fl_ensure_gtk_init();
95
96 g_autoptr(FlDartProject) project = fl_dart_project_new();
97 FlView* view = fl_view_new(project);
98
99 FlEngine* engine = fl_view_get_engine(view);
100 g_autoptr(GError) error = nullptr;
101 EXPECT_TRUE(fl_engine_start(engine, &error));
102
103 FlutterSemanticsNode2 root_node = {
104 .id = 0,
105 .label = "root",
106 };
107 FlutterSemanticsNode2* nodes[1] = {&root_node};
108 FlutterSemanticsUpdate2 update = {
109 .node_count = 1, .nodes = nodes, .view_id = 99};
110 g_signal_emit_by_name(engine, "update-semantics", &update);
111
112 FlViewAccessible* accessible = fl_view_get_accessible(view);
113 EXPECT_EQ(atk_object_get_n_accessible_children(ATK_OBJECT(accessible)), 0);
114 }
115
116 // Check secondary view is registered with engine.
117 TEST(FlViewTest, SecondaryView) {
118 flutter::testing::fl_ensure_gtk_init();
119
120 g_autoptr(FlDartProject) project = fl_dart_project_new();
121 FlView* implicit_view = fl_view_new(project);
122
123 FlEngine* engine = fl_view_get_engine(implicit_view);
124
125 FlutterViewId view_id = -1;
126 fl_engine_get_embedder_api(engine)->AddView = MOCK_ENGINE_PROC(
127 AddView, ([&view_id](auto engine, const FlutterAddViewInfo* info) {
128 view_id = info->view_id;
129 FlutterAddViewResult result = {
130 .struct_size = sizeof(FlutterAddViewResult),
131 .added = true,
132 .user_data = info->user_data};
133 info->add_view_callback(&result);
134 return kSuccess;
135 }));
136
137 g_autoptr(GError) error = nullptr;
138 EXPECT_TRUE(fl_engine_start(engine, &error));
139
140 FlView* secondary_view = fl_view_new_for_engine(engine);
141 EXPECT_EQ(view_id, fl_view_get_id(secondary_view));
142 }
143
144 // Check secondary view that fails registration.
145 TEST(FlViewTest, SecondaryViewError) {
146 flutter::testing::fl_ensure_gtk_init();
147
148 g_autoptr(FlDartProject) project = fl_dart_project_new();
149 FlView* implicit_view = fl_view_new(project);
150
151 FlEngine* engine = fl_view_get_engine(implicit_view);
152
153 FlutterViewId view_id = -1;
154 fl_engine_get_embedder_api(engine)->AddView = MOCK_ENGINE_PROC(
155 AddView, ([&view_id](auto engine, const FlutterAddViewInfo* info) {
156 view_id = info->view_id;
157 return kInvalidArguments;
158 }));
159
160 g_autoptr(GError) error = nullptr;
161 EXPECT_TRUE(fl_engine_start(engine, &error));
162
163 FlView* secondary_view = fl_view_new_for_engine(engine);
164 EXPECT_EQ(view_id, fl_view_get_id(secondary_view));
165 }
166
167 // Check views are deregistered on destruction.
168 TEST(FlViewTest, ViewDestroy) {
169 flutter::testing::fl_ensure_gtk_init();
170
171 g_autoptr(FlDartProject) project = fl_dart_project_new();
172 FlView* implicit_view = fl_view_new(project);
173
174 FlEngine* engine = fl_view_get_engine(implicit_view);
175
176 g_autoptr(GPtrArray) removed_views = g_ptr_array_new();
177 fl_engine_get_embedder_api(engine)->RemoveView = MOCK_ENGINE_PROC(
178 RemoveView,
179 ([removed_views](auto engine, const FlutterRemoveViewInfo* info) {
180 g_ptr_array_add(removed_views, GINT_TO_POINTER(info->view_id));
181 return kSuccess;
182 }));
183
184 g_autoptr(GError) error = nullptr;
185 EXPECT_TRUE(fl_engine_start(engine, &error));
186
187 FlView* secondary_view = fl_view_new_for_engine(engine);
188
189 int64_t implicit_view_id = fl_view_get_id(implicit_view);
190 int64_t secondary_view_id = fl_view_get_id(secondary_view);
191
192 fl_gtk_widget_destroy(GTK_WIDGET(secondary_view));
193 fl_gtk_widget_destroy(GTK_WIDGET(implicit_view));
194
195 EXPECT_EQ(removed_views->len, 2u);
196 EXPECT_EQ(GPOINTER_TO_INT(g_ptr_array_index(removed_views, 0)),
197 secondary_view_id);
198 EXPECT_EQ(GPOINTER_TO_INT(g_ptr_array_index(removed_views, 1)),
199 implicit_view_id);
200 }
201
202 // Check views deregistered with errors works.
203 TEST(FlViewTest, ViewDestroyError) {
204 flutter::testing::fl_ensure_gtk_init();
205
206 g_autoptr(FlDartProject) project = fl_dart_project_new();
207 FlView* implicit_view = fl_view_new(project);
208
209 FlEngine* engine = fl_view_get_engine(implicit_view);
210
211 fl_engine_get_embedder_api(engine)->RemoveView = MOCK_ENGINE_PROC(
212 RemoveView, ([](auto engine, const FlutterRemoveViewInfo* info) {
213 return kInvalidArguments;
214 }));
215
216 g_autoptr(GError) error = nullptr;
217 EXPECT_TRUE(fl_engine_start(engine, &error));
218
219 FlView* secondary_view = fl_view_new_for_engine(engine);
220
221 fl_gtk_widget_destroy(GTK_WIDGET(secondary_view));
222 fl_gtk_widget_destroy(GTK_WIDGET(implicit_view));
223 }
view
FlView * view
Definition: fl_application.cc:36
fl_dart_project_new
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
Definition: fl_dart_project.cc:50
fl_engine_get_embedder_api
FlutterEngineProcTable * fl_engine_get_embedder_api(FlEngine *self)
Definition: fl_engine.cc:726
fl_engine_start
gboolean fl_engine_start(FlEngine *self, GError **error)
Definition: fl_engine.cc:613
fl_engine_private.h
user_data
G_BEGIN_DECLS G_MODULE_EXPORT FlValue gpointer user_data
Definition: fl_event_channel.h:90
TRUE
return TRUE
Definition: fl_pixel_buffer_texture_test.cc:53
error
const uint8_t uint32_t uint32_t GError ** error
Definition: fl_pixel_buffer_texture_test.cc:40
fl_renderable_redraw
void fl_renderable_redraw(FlRenderable *self)
Definition: fl_renderable.cc:11
fl_view_get_accessible
FlViewAccessible * fl_view_get_accessible(FlView *self)
Definition: fl_view.cc:805
fl_view_new
G_MODULE_EXPORT FlView * fl_view_new(FlDartProject *project)
Definition: fl_view.cc:751
fl_view_new_for_engine
G_MODULE_EXPORT FlView * fl_view_new_for_engine(FlEngine *engine)
Definition: fl_view.cc:772
fl_view_get_engine
G_MODULE_EXPORT FlEngine * fl_view_get_engine(FlView *self)
Definition: fl_view.cc:787
fl_view_get_id
G_MODULE_EXPORT int64_t fl_view_get_id(FlView *self)
Definition: fl_view.cc:793
fl_view.h
view_id
G_BEGIN_DECLS FlutterViewId view_id
Definition: fl_view_accessible.h:49
fl_view_private.h
first_frame_cb
static void first_frame_cb(FlView *view, gboolean *first_frame_emitted)
Definition: fl_view_test.cc:15
TEST
TEST(FlViewTest, GetEngine)
Definition: fl_view_test.cc:19