Flutter Engine
fl_method_channel_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 // Included first as it collides with the X11 headers.
6 #include "gtest/gtest.h"
7 
8 #include "flutter/shell/platform/linux/fl_binary_messenger_private.h"
9 #include "flutter/shell/platform/linux/fl_engine_private.h"
10 #include "flutter/shell/platform/linux/fl_method_codec_private.h"
11 #include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h"
12 #include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h"
13 #include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h"
14 #include "flutter/shell/platform/linux/testing/mock_renderer.h"
15 
16 // Creates a mock engine that responds to platform messages.
17 static FlEngine* make_mock_engine() {
18  g_autoptr(FlDartProject) project = fl_dart_project_new();
19  g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
20  g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer));
21  g_autoptr(GError) engine_error = nullptr;
22  EXPECT_TRUE(fl_engine_start(engine, &engine_error));
23  EXPECT_EQ(engine_error, nullptr);
24 
25  return static_cast<FlEngine*>(g_object_ref(engine));
26 }
27 
28 // Called when when the method call response is received in the InvokeMethod
29 // test.
30 static void method_response_cb(GObject* object,
31  GAsyncResult* result,
32  gpointer user_data) {
33  g_autoptr(GError) error = nullptr;
34  g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(
35  FL_METHOD_CHANNEL(object), result, &error);
36  EXPECT_NE(response, nullptr);
37  EXPECT_EQ(error, nullptr);
38 
40  EXPECT_NE(r, nullptr);
41  EXPECT_EQ(error, nullptr);
42 
44  EXPECT_STREQ(fl_value_get_string(r), "Hello World!");
45 
46  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
47 }
48 
49 // Checks if invoking a method returns a value.
50 TEST(FlMethodChannelTest, InvokeMethod) {
51  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
52 
53  g_autoptr(FlEngine) engine = make_mock_engine();
54  FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
55  g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
56  g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
57  messenger, "test/standard-method", FL_METHOD_CODEC(codec));
58 
59  g_autoptr(FlValue) args = fl_value_new_string("Hello World!");
60  fl_method_channel_invoke_method(channel, "Echo", args, nullptr,
61  method_response_cb, loop);
62 
63  // Blocks here until method_response_cb is called.
64  g_main_loop_run(loop);
65 }
66 
67 // Called when when the method call response is received in the
68 // InvokeMethodNullptrArgsMessage test.
69 static void nullptr_args_response_cb(GObject* object,
70  GAsyncResult* result,
71  gpointer user_data) {
72  g_autoptr(GError) error = nullptr;
73  g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(
74  FL_METHOD_CHANNEL(object), result, &error);
75  EXPECT_NE(response, nullptr);
76  EXPECT_EQ(error, nullptr);
77 
79  EXPECT_NE(r, nullptr);
80  EXPECT_EQ(error, nullptr);
82 
83  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
84 }
85 
86 // Checks if a method can be invoked with nullptr for arguments.
87 TEST(FlMethodChannelTest, InvokeMethodNullptrArgsMessage) {
88  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
89 
90  g_autoptr(FlEngine) engine = make_mock_engine();
91  FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
92  g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
93  g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
94  messenger, "test/standard-method", FL_METHOD_CODEC(codec));
95 
96  fl_method_channel_invoke_method(channel, "Echo", nullptr, nullptr,
98 
99  // Blocks here until nullptr_args_response_cb is called.
100  g_main_loop_run(loop);
101 }
102 
103 // Called when when the method call response is received in the
104 // InvokeMethodError test.
105 static void error_response_cb(GObject* object,
106  GAsyncResult* result,
107  gpointer user_data) {
108  g_autoptr(GError) error = nullptr;
109  g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(
110  FL_METHOD_CHANNEL(object), result, &error);
111  EXPECT_NE(response, nullptr);
112  EXPECT_EQ(error, nullptr);
113 
114  EXPECT_TRUE(FL_IS_METHOD_ERROR_RESPONSE(response));
115  EXPECT_STREQ(
116  fl_method_error_response_get_code(FL_METHOD_ERROR_RESPONSE(response)),
117  "CODE");
118  EXPECT_STREQ(
119  fl_method_error_response_get_message(FL_METHOD_ERROR_RESPONSE(response)),
120  "MESSAGE");
121  FlValue* details =
122  fl_method_error_response_get_details(FL_METHOD_ERROR_RESPONSE(response));
123  EXPECT_NE(details, nullptr);
124  EXPECT_EQ(fl_value_get_type(details), FL_VALUE_TYPE_STRING);
125  EXPECT_STREQ(fl_value_get_string(details), "DETAILS");
126 
127  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
128 }
129 
130 // Checks if an error response from a method call is handled.
131 TEST(FlMethodChannelTest, InvokeMethodError) {
132  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
133 
134  g_autoptr(FlEngine) engine = make_mock_engine();
135  FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
136  g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
137  g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
138  messenger, "test/standard-method", FL_METHOD_CODEC(codec));
139 
140  g_autoptr(FlValue) args = fl_value_new_list();
144  fl_method_channel_invoke_method(channel, "Error", args, nullptr,
145  error_response_cb, loop);
146 
147  // Blocks here until error_response_cb is called.
148  g_main_loop_run(loop);
149 }
150 
151 // Called when when the method call response is received in the
152 // InvokeMethodNotImplemented test.
153 static void not_implemented_response_cb(GObject* object,
154  GAsyncResult* result,
155  gpointer user_data) {
156  g_autoptr(GError) error = nullptr;
157  g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(
158  FL_METHOD_CHANNEL(object), result, &error);
159  EXPECT_NE(response, nullptr);
160  EXPECT_EQ(error, nullptr);
161 
162  EXPECT_TRUE(FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response));
163 
164  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
165 }
166 
167 // Checks if a not implemeneted response from a method call is handled.
168 TEST(FlMethodChannelTest, InvokeMethodNotImplemented) {
169  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
170 
171  g_autoptr(FlEngine) engine = make_mock_engine();
172  FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
173  g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
174  g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
175  messenger, "test/standard-method", FL_METHOD_CODEC(codec));
176 
177  fl_method_channel_invoke_method(channel, "NotImplemented", nullptr, nullptr,
179 
180  // Blocks here until not_implemented_response_cb is called.
181  g_main_loop_run(loop);
182 }
183 
184 // Called when when the method call response is received in the
185 // InvokeMethodFailure test.
186 static void failure_response_cb(GObject* object,
187  GAsyncResult* result,
188  gpointer user_data) {
189  g_autoptr(GError) error = nullptr;
190  g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(
191  FL_METHOD_CHANNEL(object), result, &error);
192  EXPECT_EQ(response, nullptr);
193  EXPECT_NE(error, nullptr);
194 
195  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
196 }
197 
198 // Checks if an engine failure calling a method call is handled.
199 TEST(FlMethodChannelTest, InvokeMethodFailure) {
200  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
201 
202  g_autoptr(FlEngine) engine = make_mock_engine();
203  FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
204  g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
205  g_autoptr(FlMethodChannel) channel =
206  fl_method_channel_new(messenger, "test/failure", FL_METHOD_CODEC(codec));
207 
208  fl_method_channel_invoke_method(channel, "Echo", nullptr, nullptr,
209  failure_response_cb, loop);
210 
211  // Blocks here until failure_response_cb is called.
212  g_main_loop_run(loop);
213 }
214 
215 // Called when a method call is received from the engine in the
216 // ReceiveMethodCallRespondSuccess test.
217 static void method_call_success_cb(FlMethodChannel* channel,
218  FlMethodCall* method_call,
219  gpointer user_data) {
220  EXPECT_STREQ(fl_method_call_get_name(method_call), "Foo");
221  EXPECT_EQ(fl_value_get_type(fl_method_call_get_args(method_call)),
223  EXPECT_STREQ(fl_value_get_string(fl_method_call_get_args(method_call)),
224  "Marco!");
225 
226  g_autoptr(FlValue) result = fl_value_new_string("Polo!");
227  g_autoptr(GError) error = nullptr;
228  EXPECT_TRUE(fl_method_call_respond_success(method_call, result, &error));
229  EXPECT_EQ(error, nullptr);
230 }
231 
232 // Called when a the test engine notifies us what response we sent in the
233 // ReceiveMethodCallRespondSuccess test.
235  FlBinaryMessenger* messenger,
236  const gchar* channel,
237  GBytes* message,
238  FlBinaryMessengerResponseHandle* response_handle,
239  gpointer user_data) {
240  g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
241  g_autoptr(GError) error = nullptr;
242  g_autoptr(FlMethodResponse) response =
243  fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error);
244  EXPECT_NE(response, nullptr);
245  EXPECT_EQ(error, nullptr);
246 
247  EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
249  FL_METHOD_SUCCESS_RESPONSE(response));
250  EXPECT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_STRING);
251  EXPECT_STREQ(fl_value_get_string(result), "Polo!");
252 
253  fl_binary_messenger_send_response(messenger, response_handle, nullptr,
254  nullptr);
255 
256  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
257 }
258 
259 // Checks the shell able to receive and respond to method calls from the engine.
260 TEST(FlMethodChannelTest, ReceiveMethodCallRespondSuccess) {
261  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
262 
263  g_autoptr(FlEngine) engine = make_mock_engine();
264  FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
265  g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
266  g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
267  messenger, "test/standard-method", FL_METHOD_CODEC(codec));
269  nullptr, nullptr);
270 
271  // Listen for response from the engine.
273  messenger, "test/responses", method_call_success_response_cb, loop,
274  nullptr);
275 
276  // Trigger the engine to make a method call.
277  g_autoptr(FlValue) args = fl_value_new_list();
278  fl_value_append_take(args, fl_value_new_string("test/standard-method"));
281  fl_method_channel_invoke_method(channel, "InvokeMethod", args, nullptr,
282  nullptr, loop);
283 
284  // Blocks here until method_call_success_response_cb is called.
285  g_main_loop_run(loop);
286 }
287 
288 // Called when a method call is received from the engine in the
289 // ReceiveMethodCallRespondError test.
290 static void method_call_error_cb(FlMethodChannel* channel,
291  FlMethodCall* method_call,
292  gpointer user_data) {
293  EXPECT_STREQ(fl_method_call_get_name(method_call), "Foo");
294  EXPECT_EQ(fl_value_get_type(fl_method_call_get_args(method_call)),
296  EXPECT_STREQ(fl_value_get_string(fl_method_call_get_args(method_call)),
297  "Marco!");
298 
299  g_autoptr(FlValue) details = fl_value_new_string("DETAILS");
300  g_autoptr(GError) error = nullptr;
301  EXPECT_TRUE(fl_method_call_respond_error(method_call, "CODE", "MESSAGE",
302  details, &error));
303  EXPECT_EQ(error, nullptr);
304 }
305 
306 // Called when a the test engine notifies us what response we sent in the
307 // ReceiveMethodCallRespondError test.
309  FlBinaryMessenger* messenger,
310  const gchar* channel,
311  GBytes* message,
312  FlBinaryMessengerResponseHandle* response_handle,
313  gpointer user_data) {
314  g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
315  g_autoptr(GError) error = nullptr;
316  g_autoptr(FlMethodResponse) response =
317  fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error);
318  EXPECT_NE(response, nullptr);
319  EXPECT_EQ(error, nullptr);
320 
321  EXPECT_TRUE(FL_IS_METHOD_ERROR_RESPONSE(response));
322  EXPECT_STREQ(
323  fl_method_error_response_get_code(FL_METHOD_ERROR_RESPONSE(response)),
324  "CODE");
325  EXPECT_STREQ(
326  fl_method_error_response_get_message(FL_METHOD_ERROR_RESPONSE(response)),
327  "MESSAGE");
328  FlValue* details =
329  fl_method_error_response_get_details(FL_METHOD_ERROR_RESPONSE(response));
330  EXPECT_EQ(fl_value_get_type(details), FL_VALUE_TYPE_STRING);
331  EXPECT_STREQ(fl_value_get_string(details), "DETAILS");
332 
333  fl_binary_messenger_send_response(messenger, response_handle, nullptr,
334  nullptr);
335 
336  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
337 }
338 
339 // Checks the shell able to receive and respond to method calls from the engine.
340 TEST(FlMethodChannelTest, ReceiveMethodCallRespondError) {
341  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
342 
343  g_autoptr(FlEngine) engine = make_mock_engine();
344  FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
345  g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
346  g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
347  messenger, "test/standard-method", FL_METHOD_CODEC(codec));
349  nullptr, nullptr);
350 
351  // Listen for response from the engine.
353  messenger, "test/responses", method_call_error_response_cb, loop,
354  nullptr);
355 
356  // Trigger the engine to make a method call.
357  g_autoptr(FlValue) args = fl_value_new_list();
358  fl_value_append_take(args, fl_value_new_string("test/standard-method"));
361  fl_method_channel_invoke_method(channel, "InvokeMethod", args, nullptr,
362  nullptr, loop);
363 
364  // Blocks here until method_call_error_response_cb is called.
365  g_main_loop_run(loop);
366 }
367 
368 // Called when a method call is received from the engine in the
369 // ReceiveMethodCallRespondNotImplemented test.
370 static void method_call_not_implemented_cb(FlMethodChannel* channel,
371  FlMethodCall* method_call,
372  gpointer user_data) {
373  EXPECT_STREQ(fl_method_call_get_name(method_call), "Foo");
374  EXPECT_EQ(fl_value_get_type(fl_method_call_get_args(method_call)),
376  EXPECT_STREQ(fl_value_get_string(fl_method_call_get_args(method_call)),
377  "Marco!");
378 
379  g_autoptr(GError) error = nullptr;
380  EXPECT_TRUE(fl_method_call_respond_not_implemented(method_call, &error));
381  EXPECT_EQ(error, nullptr);
382 }
383 
384 // Called when a the test engine notifies us what response we sent in the
385 // ReceiveMethodCallRespondNotImplemented test.
387  FlBinaryMessenger* messenger,
388  const gchar* channel,
389  GBytes* message,
390  FlBinaryMessengerResponseHandle* response_handle,
391  gpointer user_data) {
392  g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
393  g_autoptr(GError) error = nullptr;
394  g_autoptr(FlMethodResponse) response =
395  fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error);
396  EXPECT_NE(response, nullptr);
397  EXPECT_EQ(error, nullptr);
398 
399  EXPECT_TRUE(FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response));
400 
401  fl_binary_messenger_send_response(messenger, response_handle, nullptr,
402  nullptr);
403 
404  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
405 }
406 
407 // Checks the shell able to receive and respond to method calls from the engine.
408 TEST(FlMethodChannelTest, ReceiveMethodCallRespondNotImplemented) {
409  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
410 
411  g_autoptr(FlEngine) engine = make_mock_engine();
412  FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
413  g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
414  g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
415  messenger, "test/standard-method", FL_METHOD_CODEC(codec));
417  channel, method_call_not_implemented_cb, nullptr, nullptr);
418 
419  // Listen for response from the engine.
421  messenger, "test/responses", method_call_not_implemented_response_cb,
422  loop, nullptr);
423 
424  // Trigger the engine to make a method call.
425  g_autoptr(FlValue) args = fl_value_new_list();
426  fl_value_append_take(args, fl_value_new_string("test/standard-method"));
429  fl_method_channel_invoke_method(channel, "InvokeMethod", args, nullptr,
430  nullptr, loop);
431 
432  // Blocks here until method_call_not_implemented_response_cb is called.
433  g_main_loop_run(loop);
434 }
435 
436 // A test method codec that always generates errors on responses.
437 G_DECLARE_FINAL_TYPE(TestMethodCodec,
438  test_method_codec,
439  TEST,
440  METHOD_CODEC,
441  FlMethodCodec)
442 
443 struct _TestMethodCodec {
444  FlMethodCodec parent_instance;
445 
446  FlStandardMethodCodec* wrapped_codec;
447 };
448 
449 G_DEFINE_TYPE(TestMethodCodec, test_method_codec, fl_method_codec_get_type())
450 
451 static void test_method_codec_dispose(GObject* object) {
452  TestMethodCodec* self = TEST_METHOD_CODEC(object);
453 
454  g_clear_object(&self->wrapped_codec);
455 
456  G_OBJECT_CLASS(test_method_codec_parent_class)->dispose(object);
457 }
458 
459 // Implements FlMethodCodec::encode_method_call.
460 static GBytes* test_method_codec_encode_method_call(FlMethodCodec* codec,
461  const gchar* name,
462  FlValue* args,
463  GError** error) {
464  EXPECT_TRUE(TEST_IS_METHOD_CODEC(codec));
465  TestMethodCodec* self = TEST_METHOD_CODEC(codec);
467  FL_METHOD_CODEC(self->wrapped_codec), name, args, error);
468 }
469 
470 // Implements FlMethodCodec::decode_method_call.
471 static gboolean test_method_codec_decode_method_call(FlMethodCodec* codec,
472  GBytes* message,
473  gchar** name,
474  FlValue** args,
475  GError** error) {
476  EXPECT_TRUE(TEST_IS_METHOD_CODEC(codec));
477  TestMethodCodec* self = TEST_METHOD_CODEC(codec);
479  FL_METHOD_CODEC(self->wrapped_codec), message, name, args, error);
480 }
481 
482 // Implements FlMethodCodec::encode_success_envelope.
483 static GBytes* test_method_codec_encode_success_envelope(FlMethodCodec* codec,
484  FlValue* result,
485  GError** error) {
487  "Unsupported type");
488  return nullptr;
489 }
490 
491 // Implements FlMethodCodec::encode_error_envelope.
492 static GBytes* test_method_codec_encode_error_envelope(FlMethodCodec* codec,
493  const gchar* code,
494  const gchar* message,
495  FlValue* details,
496  GError** error) {
498  "Unsupported type");
499  return nullptr;
500 }
501 
502 // Implements FlMethodCodec::encode_decode_reponse.
503 static FlMethodResponse* test_method_codec_decode_response(FlMethodCodec* codec,
504  GBytes* message,
505  GError** error) {
506  EXPECT_TRUE(TEST_IS_METHOD_CODEC(codec));
507  TestMethodCodec* self = TEST_METHOD_CODEC(codec);
508  return fl_method_codec_decode_response(FL_METHOD_CODEC(self->wrapped_codec),
509  message, error);
510 }
511 
512 static void test_method_codec_class_init(TestMethodCodecClass* klass) {
513  G_OBJECT_CLASS(klass)->dispose = test_method_codec_dispose;
514  FL_METHOD_CODEC_CLASS(klass)->encode_method_call =
516  FL_METHOD_CODEC_CLASS(klass)->decode_method_call =
518  FL_METHOD_CODEC_CLASS(klass)->encode_success_envelope =
520  FL_METHOD_CODEC_CLASS(klass)->encode_error_envelope =
522  FL_METHOD_CODEC_CLASS(klass)->decode_response =
524 }
525 
526 static void test_method_codec_init(TestMethodCodec* self) {
527  self->wrapped_codec = fl_standard_method_codec_new();
528 }
529 
530 TestMethodCodec* test_method_codec_new() {
531  return TEST_METHOD_CODEC(g_object_new(test_method_codec_get_type(), nullptr));
532 }
533 
534 // Called when a method call is received from the engine in the
535 // ReceiveMethodCallRespondSuccessError test.
536 static void method_call_success_error_cb(FlMethodChannel* channel,
537  FlMethodCall* method_call,
538  gpointer user_data) {
539  g_autoptr(FlValue) result = fl_value_new_int(42);
540  g_autoptr(GError) response_error = nullptr;
541  EXPECT_FALSE(
542  fl_method_call_respond_success(method_call, result, &response_error));
543  EXPECT_NE(response_error, nullptr);
544 
545  // Respond to stop a warning occuring about not responding.
546  fl_method_call_respond_not_implemented(method_call, nullptr);
547 
548  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
549 }
550 
551 // Checks error correctly handled if provide an unsupported arg in a method call
552 // response.
553 TEST(FlMethodChannelTest, ReceiveMethodCallRespondSuccessError) {
554  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
555 
556  g_autoptr(FlEngine) engine = make_mock_engine();
557  FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
558  g_autoptr(TestMethodCodec) codec = test_method_codec_new();
559  g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
560  messenger, "test/standard-method", FL_METHOD_CODEC(codec));
562  channel, method_call_success_error_cb, loop, nullptr);
563 
564  // Trigger the engine to make a method call.
565  g_autoptr(FlValue) args = fl_value_new_list();
566  fl_value_append_take(args, fl_value_new_string("test/standard-method"));
569  fl_method_channel_invoke_method(channel, "InvokeMethod", args, nullptr,
570  nullptr, loop);
571 
572  // Blocks here until method_call_success_error_cb is called.
573  g_main_loop_run(loop);
574 }
575 
576 // Called when a method call is received from the engine in the
577 // ReceiveMethodCallRespondErrorError test.
578 static void method_call_error_error_cb(FlMethodChannel* channel,
579  FlMethodCall* method_call,
580  gpointer user_data) {
581  g_autoptr(FlValue) details = fl_value_new_int(42);
582  g_autoptr(GError) response_error = nullptr;
583  EXPECT_FALSE(fl_method_call_respond_error(method_call, "error", "ERROR",
584  details, &response_error));
585  EXPECT_NE(response_error, nullptr);
586 
587  // Respond to stop a warning occuring about not responding.
588  fl_method_call_respond_not_implemented(method_call, nullptr);
589 
590  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
591 }
592 
593 // Checks error correctly handled if provide an unsupported arg in a method call
594 // response.
595 TEST(FlMethodChannelTest, ReceiveMethodCallRespondErrorError) {
596  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
597 
598  g_autoptr(FlEngine) engine = make_mock_engine();
599  FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
600  g_autoptr(TestMethodCodec) codec = test_method_codec_new();
601  g_autoptr(FlMethodChannel) channel = fl_method_channel_new(
602  messenger, "test/standard-method", FL_METHOD_CODEC(codec));
604  loop, nullptr);
605 
606  // Trigger the engine to make a method call.
607  g_autoptr(FlValue) args = fl_value_new_list();
608  fl_value_append_take(args, fl_value_new_string("test/standard-method"));
611  fl_method_channel_invoke_method(channel, "InvokeMethod", args, nullptr,
612  nullptr, loop);
613 
614  // Blocks here until method_call_error_error_cb is called.
615  g_main_loop_run(loop);
616 }
G_MODULE_EXPORT FlValue * fl_value_new_list()
Definition: fl_value.cc:310
G_BEGIN_DECLS FlValue * args
static void error_response_cb(GObject *object, GAsyncResult *result, gpointer user_data)
G_MODULE_EXPORT void fl_binary_messenger_set_message_handler_on_channel(FlBinaryMessenger *self, const gchar *channel, FlBinaryMessengerMessageHandler handler, gpointer user_data, GDestroyNotify destroy_notify)
GBytes * fl_method_codec_encode_method_call(FlMethodCodec *self, const gchar *name, FlValue *args, GError **error)
G_BEGIN_DECLS FlMethodCall * method_call
G_MODULE_EXPORT FlMethodResponse * fl_method_channel_invoke_method_finish(FlMethodChannel *self, GAsyncResult *result, GError **error)
static void method_call_not_implemented_response_cb(FlBinaryMessenger *messenger, const gchar *channel, GBytes *message, FlBinaryMessengerResponseHandle *response_handle, gpointer user_data)
G_MODULE_EXPORT FlValueType fl_value_get_type(FlValue *self)
Definition: fl_value.cc:395
FlMockRenderer * fl_mock_renderer_new()
static void test_method_codec_class_init(TestMethodCodecClass *klass)
G_MODULE_EXPORT gboolean fl_method_call_respond_not_implemented(FlMethodCall *self, GError **error)
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:39
FlMethodResponse GError ** error
G_MODULE_EXPORT gboolean fl_method_call_respond_success(FlMethodCall *self, FlValue *result, GError **error)
static void test_method_codec_init(TestMethodCodec *self)
static void failure_response_cb(GObject *object, GAsyncResult *result, gpointer user_data)
G_MODULE_EXPORT FlValue * fl_method_success_response_get_result(FlMethodSuccessResponse *self)
static void method_call_success_error_cb(FlMethodChannel *channel, FlMethodCall *method_call, gpointer user_data)
#define FL_MESSAGE_CODEC_ERROR
G_MODULE_EXPORT const gchar * fl_method_error_response_get_message(FlMethodErrorResponse *self)
static void method_call_success_response_cb(FlBinaryMessenger *messenger, const gchar *channel, GBytes *message, FlBinaryMessengerResponseHandle *response_handle, gpointer user_data)
G_MODULE_EXPORT FlValue * fl_method_call_get_args(FlMethodCall *self)
static void method_call_error_cb(FlMethodChannel *channel, FlMethodCall *method_call, gpointer user_data)
TestMethodCodec * test_method_codec_new()
G_MODULE_EXPORT gboolean fl_binary_messenger_send_response(FlBinaryMessenger *self, FlBinaryMessengerResponseHandle *response_handle, GBytes *response, GError **error)
G_MODULE_EXPORT FlStandardMethodCodec * fl_standard_method_codec_new()
G_BEGIN_DECLS FlValue gpointer user_data
G_MODULE_EXPORT void fl_value_append_take(FlValue *self, FlValue *value)
Definition: fl_value.cc:514
gboolean fl_engine_start(FlEngine *self, GError **error)
Definition: fl_engine.cc:352
static void method_response_cb(GObject *object, GAsyncResult *result, gpointer user_data)
static void not_implemented_response_cb(GObject *object, GAsyncResult *result, gpointer user_data)
G_MODULE_EXPORT void fl_method_channel_set_method_call_handler(FlMethodChannel *self, FlMethodChannelMethodCallHandler handler, gpointer user_data, GDestroyNotify destroy_notify)
G_MODULE_EXPORT const gchar * fl_method_call_get_name(FlMethodCall *self)
G_MODULE_EXPORT FlMethodChannel * fl_method_channel_new(FlBinaryMessenger *messenger, const gchar *name, FlMethodCodec *codec)
static gboolean test_method_codec_decode_method_call(FlMethodCodec *codec, GBytes *message, gchar **name, FlValue **args, GError **error)
static void method_call_success_cb(FlMethodChannel *channel, FlMethodCall *method_call, gpointer user_data)
G_MODULE_EXPORT gboolean fl_method_call_respond_error(FlMethodCall *self, const gchar *code, const gchar *message, FlValue *details, GError **error)
static void method_call_error_error_cb(FlMethodChannel *channel, FlMethodCall *method_call, gpointer user_data)
FlMethodResponse * fl_method_codec_decode_response(FlMethodCodec *self, GBytes *message, GError **error)
static GBytes * test_method_codec_encode_method_call(FlMethodCodec *codec, const gchar *name, FlValue *args, GError **error)
G_MODULE_EXPORT FlValue * fl_value_new_int(int64_t value)
Definition: fl_value.cc:233
TEST(FlMethodChannelTest, InvokeMethod)
G_MODULE_EXPORT FlValue * fl_value_new_string(const gchar *value)
Definition: fl_value.cc:247
G_MODULE_EXPORT void fl_method_channel_invoke_method(FlMethodChannel *self, const gchar *method, FlValue *args, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
const char * name
Definition: fuchsia.cc:50
FlEngine * fl_engine_new(FlDartProject *project, FlRenderer *renderer)
Definition: fl_engine.cc:337
G_DEFINE_TYPE(FlBasicMessageChannelResponseHandle, fl_basic_message_channel_response_handle, G_TYPE_OBJECT) static void fl_basic_message_channel_response_handle_dispose(GObject *object)
G_MODULE_EXPORT const gchar * fl_value_get_string(FlValue *self)
Definition: fl_value.cc:596
G_MODULE_EXPORT const gchar * fl_method_error_response_get_code(FlMethodErrorResponse *self)
static FlMethodResponse * test_method_codec_decode_response(FlMethodCodec *codec, GBytes *message, GError **error)
static GBytes * test_method_codec_encode_success_envelope(FlMethodCodec *codec, FlValue *result, GError **error)
G_MODULE_EXPORT FlValue * fl_method_response_get_result(FlMethodResponse *self, GError **error)
static void nullptr_args_response_cb(GObject *object, GAsyncResult *result, gpointer user_data)
G_MODULE_EXPORT GType fl_method_codec_get_type()
static void test_method_codec_dispose(GObject *object)
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
static GBytes * test_method_codec_encode_error_envelope(FlMethodCodec *codec, const gchar *code, const gchar *message, FlValue *details, GError **error)
FlBinaryMessenger * fl_binary_messenger_new(FlEngine *engine)
static FlEngine * make_mock_engine()
gboolean fl_method_codec_decode_method_call(FlMethodCodec *self, GBytes *message, gchar **name, FlValue **args, GError **error)
G_DECLARE_FINAL_TYPE(TestMethodCodec, test_method_codec, TEST, METHOD_CODEC, FlMethodCodec) struct _TestMethodCodec
G_MODULE_EXPORT FlValue * fl_method_error_response_get_details(FlMethodErrorResponse *self)
static void method_call_error_response_cb(FlBinaryMessenger *messenger, const gchar *channel, GBytes *message, FlBinaryMessengerResponseHandle *response_handle, gpointer user_data)
static void method_call_not_implemented_cb(FlMethodChannel *channel, FlMethodCall *method_call, gpointer user_data)