Flutter Linux Embedder
fl_accessible_text_field_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/embedder/test_utils/proc_table_replacement.h"
12 #include "flutter/shell/platform/linux/testing/mock_signal_handler.h"
13 
14 // MOCK_ENGINE_PROC is leaky by design
15 // NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)
16 
17 static FlValue* decode_semantic_data(const uint8_t* data, size_t data_length) {
18  g_autoptr(GBytes) bytes = g_bytes_new(data, data_length);
19  g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new();
20  return fl_message_codec_decode_message(FL_MESSAGE_CODEC(codec), bytes,
21  nullptr);
22 }
23 
24 // Tests that semantic node value updates from Flutter emit AtkText::text-insert
25 // and AtkText::text-remove signals as expected.
26 TEST(FlAccessibleTextFieldTest, SetValue) {
27  g_autoptr(FlDartProject) project = fl_dart_project_new();
28  g_autoptr(FlEngine) engine = fl_engine_new(project);
29  g_autoptr(FlAccessibleNode) node =
30  fl_accessible_text_field_new(engine, 123, 1);
31 
32  // "" -> "Flutter"
33  {
34  flutter::testing::MockSignalHandler2<int, int> text_inserted(node,
35  "text-insert");
36  flutter::testing::MockSignalHandler text_removed(node, "text-remove");
37 
38  EXPECT_SIGNAL2(text_inserted, ::testing::Eq(0), ::testing::Eq(7));
39  EXPECT_SIGNAL(text_removed).Times(0);
40 
41  fl_accessible_node_set_value(node, "Flutter");
42  }
43 
44  // "Flutter" -> "Flutter"
45  {
46  flutter::testing::MockSignalHandler text_inserted(node, "text-insert");
47  flutter::testing::MockSignalHandler text_removed(node, "text-remove");
48 
49  EXPECT_SIGNAL(text_inserted).Times(0);
50  EXPECT_SIGNAL(text_removed).Times(0);
51 
52  fl_accessible_node_set_value(node, "Flutter");
53  }
54 
55  // "Flutter" -> "engine"
56  {
57  flutter::testing::MockSignalHandler2<int, int> text_inserted(node,
58  "text-insert");
59  flutter::testing::MockSignalHandler2<int, int> text_removed(node,
60  "text-remove");
61 
62  EXPECT_SIGNAL2(text_inserted, ::testing::Eq(0), ::testing::Eq(6));
63  EXPECT_SIGNAL2(text_removed, ::testing::Eq(0), ::testing::Eq(7));
64 
65  fl_accessible_node_set_value(node, "engine");
66  }
67 
68  // "engine" -> ""
69  {
70  flutter::testing::MockSignalHandler text_inserted(node, "text-insert");
71  flutter::testing::MockSignalHandler2<int, int> text_removed(node,
72  "text-remove");
73 
74  EXPECT_SIGNAL(text_inserted).Times(0);
75  EXPECT_SIGNAL2(text_removed, ::testing::Eq(0), ::testing::Eq(6));
76 
78  }
79 }
80 
81 // Tests that semantic node selection updates from Flutter emit
82 // AtkText::text-selection-changed and AtkText::text-caret-moved signals as
83 // expected.
84 TEST(FlAccessibleTextFieldTest, SetTextSelection) {
85  g_autoptr(FlDartProject) project = fl_dart_project_new();
86  g_autoptr(FlEngine) engine = fl_engine_new(project);
87  g_autoptr(FlAccessibleNode) node =
88  fl_accessible_text_field_new(engine, 123, 1);
89 
90  // [-1,-1] -> [2,3]
91  {
92  flutter::testing::MockSignalHandler text_selection_changed(
93  node, "text-selection-changed");
94  flutter::testing::MockSignalHandler1<int> text_caret_moved(
95  node, "text-caret-moved");
96 
97  EXPECT_SIGNAL(text_selection_changed);
98  EXPECT_SIGNAL1(text_caret_moved, ::testing::Eq(3));
99 
101  }
102 
103  // [2,3] -> [3,3]
104  {
105  flutter::testing::MockSignalHandler text_selection_changed(
106  node, "text-selection-changed");
107  flutter::testing::MockSignalHandler text_caret_moved(node,
108  "text-caret-moved");
109 
110  EXPECT_SIGNAL(text_selection_changed);
111  EXPECT_SIGNAL(text_caret_moved).Times(0);
112 
114  }
115 
116  // [3,3] -> [3,3]
117  {
118  flutter::testing::MockSignalHandler text_selection_changed(
119  node, "text-selection-changed");
120  flutter::testing::MockSignalHandler text_caret_moved(node,
121  "text-caret-moved");
122 
123  EXPECT_SIGNAL(text_selection_changed).Times(0);
124  EXPECT_SIGNAL(text_caret_moved).Times(0);
125 
127  }
128 
129  // [3,3] -> [4,4]
130  {
131  flutter::testing::MockSignalHandler text_selection_changed(
132  node, "text-selection-changed");
133  flutter::testing::MockSignalHandler1<int> text_caret_moved(
134  node, "text-caret-moved");
135 
136  EXPECT_SIGNAL(text_selection_changed).Times(0);
137  EXPECT_SIGNAL1(text_caret_moved, ::testing::Eq(4));
138 
140  }
141 }
142 
143 // Tests that fl_accessible_text_field_perform_action() passes the required
144 // "expandSelection" argument for semantic cursor move actions.
145 TEST(FlAccessibleTextFieldTest, PerformAction) {
146  g_autoptr(GPtrArray) action_datas = g_ptr_array_new_with_free_func(
147  reinterpret_cast<GDestroyNotify>(fl_value_unref));
148 
149  g_autoptr(FlDartProject) project = fl_dart_project_new();
150  g_autoptr(FlEngine) engine = fl_engine_new(project);
151 
152  g_autoptr(GError) error = nullptr;
153  EXPECT_TRUE(fl_engine_start(engine, &error));
154  EXPECT_EQ(error, nullptr);
155 
156  fl_engine_get_embedder_api(engine)->SendSemanticsAction = MOCK_ENGINE_PROC(
157  SendSemanticsAction,
158  ([&action_datas](auto engine,
159  const FlutterSendSemanticsActionInfo* info) {
160  g_ptr_array_add(action_datas,
161  decode_semantic_data(info->data, info->data_length));
162  return kSuccess;
163  }));
164 
165  g_autoptr(FlAccessibleNode) node =
166  fl_accessible_text_field_new(engine, 123, 1);
168  node, static_cast<FlutterSemanticsAction>(
169  kFlutterSemanticsActionMoveCursorForwardByCharacter |
170  kFlutterSemanticsActionMoveCursorBackwardByCharacter |
171  kFlutterSemanticsActionMoveCursorForwardByWord |
172  kFlutterSemanticsActionMoveCursorBackwardByWord));
173 
174  g_autoptr(FlValue) expand_selection = fl_value_new_bool(false);
175 
176  for (int i = 0; i < 4; ++i) {
177  atk_action_do_action(ATK_ACTION(node), i);
178 
179  FlValue* data = static_cast<FlValue*>(g_ptr_array_index(action_datas, i));
180  EXPECT_NE(data, nullptr);
181  EXPECT_TRUE(fl_value_equal(data, expand_selection));
182  }
183 }
184 
185 // Tests AtkText::get_character_count.
186 TEST(FlAccessibleTextFieldTest, GetCharacterCount) {
187  g_autoptr(FlDartProject) project = fl_dart_project_new();
188  g_autoptr(FlEngine) engine = fl_engine_new(project);
189  g_autoptr(FlAccessibleNode) node =
190  fl_accessible_text_field_new(engine, 123, 1);
191 
192  EXPECT_EQ(atk_text_get_character_count(ATK_TEXT(node)), 0);
193 
194  fl_accessible_node_set_value(node, "Flutter!");
195 
196  EXPECT_EQ(atk_text_get_character_count(ATK_TEXT(node)), 8);
197 }
198 
199 // Tests AtkText::get_text.
200 TEST(FlAccessibleTextFieldTest, GetText) {
201  g_autoptr(FlDartProject) project = fl_dart_project_new();
202  g_autoptr(FlEngine) engine = fl_engine_new(project);
203  g_autoptr(FlAccessibleNode) node =
204  fl_accessible_text_field_new(engine, 123, 1);
205 
206  g_autofree gchar* empty = atk_text_get_text(ATK_TEXT(node), 0, -1);
207  EXPECT_STREQ(empty, "");
208 
209  flutter::testing::MockSignalHandler text_inserted(node, "text-insert");
210  EXPECT_SIGNAL(text_inserted).Times(1);
211 
212  fl_accessible_node_set_value(node, "Flutter!");
213 
214  g_autofree gchar* flutter = atk_text_get_text(ATK_TEXT(node), 0, -1);
215  EXPECT_STREQ(flutter, "Flutter!");
216 
217  g_autofree gchar* tt = atk_text_get_text(ATK_TEXT(node), 3, 5);
218  EXPECT_STREQ(tt, "tt");
219 }
220 
221 // Tests AtkText::get_caret_offset.
222 TEST(FlAccessibleTextFieldTest, GetCaretOffset) {
223  g_autoptr(FlDartProject) project = fl_dart_project_new();
224  g_autoptr(FlEngine) engine = fl_engine_new(project);
225  g_autoptr(FlAccessibleNode) node =
226  fl_accessible_text_field_new(engine, 123, 1);
227 
228  EXPECT_EQ(atk_text_get_caret_offset(ATK_TEXT(node)), -1);
229 
231 
232  EXPECT_EQ(atk_text_get_caret_offset(ATK_TEXT(node)), 2);
233 }
234 
235 // Tests AtkText::set_caret_offset.
236 TEST(FlAccessibleTextFieldTest, SetCaretOffset) {
237  int base = -1;
238  int extent = -1;
239 
240  g_autoptr(FlDartProject) project = fl_dart_project_new();
241  g_autoptr(FlEngine) engine = fl_engine_new(project);
242 
243  g_autoptr(GError) error = nullptr;
244  EXPECT_TRUE(fl_engine_start(engine, &error));
245  EXPECT_EQ(error, nullptr);
246 
247  fl_engine_get_embedder_api(engine)->SendSemanticsAction = MOCK_ENGINE_PROC(
248  SendSemanticsAction,
249  ([&base, &extent](auto engine,
250  const FlutterSendSemanticsActionInfo* info) {
251  EXPECT_EQ(info->action, kFlutterSemanticsActionSetSelection);
252  g_autoptr(FlValue) value =
253  decode_semantic_data(info->data, info->data_length);
256  extent = fl_value_get_int(fl_value_lookup_string(value, "extent"));
257  return kSuccess;
258  }));
259 
260  g_autoptr(FlAccessibleNode) node =
261  fl_accessible_text_field_new(engine, 123, 1);
262 
263  EXPECT_TRUE(atk_text_set_caret_offset(ATK_TEXT(node), 3));
264  EXPECT_EQ(base, 3);
265  EXPECT_EQ(extent, 3);
266 }
267 
268 // Tests AtkText::get_n_selections.
269 TEST(FlAccessibleTextFieldTest, GetNSelections) {
270  g_autoptr(FlDartProject) project = fl_dart_project_new();
271  g_autoptr(FlEngine) engine = fl_engine_new(project);
272  g_autoptr(FlAccessibleNode) node =
273  fl_accessible_text_field_new(engine, 123, 1);
274 
275  EXPECT_EQ(atk_text_get_n_selections(ATK_TEXT(node)), 0);
276 
278 
279  EXPECT_EQ(atk_text_get_n_selections(ATK_TEXT(node)), 1);
280 }
281 
282 // Tests AtkText::get_selection.
283 TEST(FlAccessibleTextFieldTest, GetSelection) {
284  g_autoptr(FlDartProject) project = fl_dart_project_new();
285  g_autoptr(FlEngine) engine = fl_engine_new(project);
286  g_autoptr(FlAccessibleNode) node =
287  fl_accessible_text_field_new(engine, 123, 1);
288 
289  EXPECT_EQ(atk_text_get_selection(ATK_TEXT(node), 0, nullptr, nullptr),
290  nullptr);
291 
292  fl_accessible_node_set_value(node, "Flutter");
294 
295  gint start, end;
296  g_autofree gchar* selection =
297  atk_text_get_selection(ATK_TEXT(node), 0, &start, &end);
298  EXPECT_STREQ(selection, "utt");
299  EXPECT_EQ(start, 2);
300  EXPECT_EQ(end, 5);
301 
302  // reverse
304  g_autofree gchar* reverse =
305  atk_text_get_selection(ATK_TEXT(node), 0, &start, &end);
306  EXPECT_STREQ(reverse, "utt");
307  EXPECT_EQ(start, 2);
308  EXPECT_EQ(end, 5);
309 
310  // empty
312  EXPECT_EQ(atk_text_get_selection(ATK_TEXT(node), 0, &start, &end), nullptr);
313 
314  // selection num != 0
315  EXPECT_EQ(atk_text_get_selection(ATK_TEXT(node), 1, &start, &end), nullptr);
316 }
317 
318 // Tests AtkText::add_selection.
319 TEST(FlAccessibleTextFieldTest, AddSelection) {
320  int base = -1;
321  int extent = -1;
322 
323  g_autoptr(FlDartProject) project = fl_dart_project_new();
324  g_autoptr(FlEngine) engine = fl_engine_new(project);
325 
326  g_autoptr(GError) error = nullptr;
327  EXPECT_TRUE(fl_engine_start(engine, &error));
328  EXPECT_EQ(error, nullptr);
329 
330  fl_engine_get_embedder_api(engine)->SendSemanticsAction = MOCK_ENGINE_PROC(
331  SendSemanticsAction,
332  ([&base, &extent](auto engine,
333  const FlutterSendSemanticsActionInfo* info) {
334  EXPECT_EQ(info->action, kFlutterSemanticsActionSetSelection);
335  g_autoptr(FlValue) value =
336  decode_semantic_data(info->data, info->data_length);
339  extent = fl_value_get_int(fl_value_lookup_string(value, "extent"));
340  return kSuccess;
341  }));
342 
343  g_autoptr(FlAccessibleNode) node =
344  fl_accessible_text_field_new(engine, 123, 1);
345 
346  EXPECT_TRUE(atk_text_add_selection(ATK_TEXT(node), 2, 4));
347  EXPECT_EQ(base, 2);
348  EXPECT_EQ(extent, 4);
349 
351 
352  // already has selection
353  EXPECT_FALSE(atk_text_add_selection(ATK_TEXT(node), 6, 7));
354  EXPECT_EQ(base, 2);
355  EXPECT_EQ(extent, 4);
356 }
357 
358 // Tests AtkText::remove_selection.
359 TEST(FlAccessibleTextFieldTest, RemoveSelection) {
360  int base = -1;
361  int extent = -1;
362 
363  g_autoptr(FlDartProject) project = fl_dart_project_new();
364  g_autoptr(FlEngine) engine = fl_engine_new(project);
365 
366  g_autoptr(GError) error = nullptr;
367  EXPECT_TRUE(fl_engine_start(engine, &error));
368  EXPECT_EQ(error, nullptr);
369 
370  fl_engine_get_embedder_api(engine)->SendSemanticsAction = MOCK_ENGINE_PROC(
371  SendSemanticsAction,
372  ([&base, &extent](auto engine,
373  const FlutterSendSemanticsActionInfo* info) {
374  EXPECT_EQ(info->action, kFlutterSemanticsActionSetSelection);
375  g_autoptr(FlValue) value =
376  decode_semantic_data(info->data, info->data_length);
379  extent = fl_value_get_int(fl_value_lookup_string(value, "extent"));
380  return kSuccess;
381  }));
382 
383  g_autoptr(FlAccessibleNode) node =
384  fl_accessible_text_field_new(engine, 123, 1);
385 
386  // no selection
387  EXPECT_FALSE(atk_text_remove_selection(ATK_TEXT(node), 0));
388  EXPECT_EQ(base, -1);
389  EXPECT_EQ(extent, -1);
390 
392 
393  // selection num != 0
394  EXPECT_FALSE(atk_text_remove_selection(ATK_TEXT(node), 1));
395  EXPECT_EQ(base, -1);
396  EXPECT_EQ(extent, -1);
397 
398  // ok, collapses selection
399  EXPECT_TRUE(atk_text_remove_selection(ATK_TEXT(node), 0));
400  EXPECT_EQ(base, 4);
401  EXPECT_EQ(extent, 4);
402 }
403 
404 // Tests AtkText::set_selection.
405 TEST(FlAccessibleTextFieldTest, SetSelection) {
406  int base = -1;
407  int extent = -1;
408 
409  g_autoptr(FlDartProject) project = fl_dart_project_new();
410  g_autoptr(FlEngine) engine = fl_engine_new(project);
411 
412  g_autoptr(GError) error = nullptr;
413  EXPECT_TRUE(fl_engine_start(engine, &error));
414  EXPECT_EQ(error, nullptr);
415 
416  fl_engine_get_embedder_api(engine)->SendSemanticsAction = MOCK_ENGINE_PROC(
417  SendSemanticsAction,
418  ([&base, &extent](auto engine,
419  const FlutterSendSemanticsActionInfo* info) {
420  EXPECT_EQ(info->action, kFlutterSemanticsActionSetSelection);
421  g_autoptr(FlValue) value =
422  decode_semantic_data(info->data, info->data_length);
425  extent = fl_value_get_int(fl_value_lookup_string(value, "extent"));
426  return kSuccess;
427  }));
428 
429  g_autoptr(FlAccessibleNode) node =
430  fl_accessible_text_field_new(engine, 123, 1);
431 
432  // selection num != 0
433  EXPECT_FALSE(atk_text_set_selection(ATK_TEXT(node), 1, 2, 4));
434  EXPECT_EQ(base, -1);
435  EXPECT_EQ(extent, -1);
436 
437  EXPECT_TRUE(atk_text_set_selection(ATK_TEXT(node), 0, 2, 4));
438  EXPECT_EQ(base, 2);
439  EXPECT_EQ(extent, 4);
440 
441  EXPECT_TRUE(atk_text_set_selection(ATK_TEXT(node), 0, 5, 1));
442  EXPECT_EQ(base, 5);
443  EXPECT_EQ(extent, 1);
444 }
445 
446 // Tests AtkEditableText::set_text_contents.
447 TEST(FlAccessibleTextFieldTest, SetTextContents) {
448  g_autofree gchar* text = nullptr;
449 
450  g_autoptr(FlDartProject) project = fl_dart_project_new();
451  g_autoptr(FlEngine) engine = fl_engine_new(project);
452 
453  g_autoptr(GError) error = nullptr;
454  EXPECT_TRUE(fl_engine_start(engine, &error));
455  EXPECT_EQ(error, nullptr);
456 
457  fl_engine_get_embedder_api(engine)->SendSemanticsAction = MOCK_ENGINE_PROC(
458  SendSemanticsAction,
459  ([&text](auto engine, const FlutterSendSemanticsActionInfo* info) {
460  EXPECT_EQ(info->action, kFlutterSemanticsActionSetText);
461  g_autoptr(FlValue) value =
462  decode_semantic_data(info->data, info->data_length);
464  text = g_strdup(fl_value_get_string(value));
465  return kSuccess;
466  }));
467 
468  g_autoptr(FlAccessibleNode) node =
469  fl_accessible_text_field_new(engine, 123, 1);
470 
471  atk_editable_text_set_text_contents(ATK_EDITABLE_TEXT(node), "Flutter");
472  EXPECT_STREQ(text, "Flutter");
473 }
474 
475 // Tests AtkEditableText::insert/delete_text.
476 TEST(FlAccessibleTextFieldTest, InsertDeleteText) {
477  g_autofree gchar* text = nullptr;
478  int base = -1;
479  int extent = -1;
480 
481  g_autoptr(FlDartProject) project = fl_dart_project_new();
482  g_autoptr(FlEngine) engine = fl_engine_new(project);
483 
484  g_autoptr(GError) error = nullptr;
485  EXPECT_TRUE(fl_engine_start(engine, &error));
486  EXPECT_EQ(error, nullptr);
487 
488  fl_engine_get_embedder_api(engine)->SendSemanticsAction = MOCK_ENGINE_PROC(
489  SendSemanticsAction,
490  ([&text, &base, &extent](auto engine,
491  const FlutterSendSemanticsActionInfo* info) {
492  EXPECT_THAT(info->action,
493  ::testing::AnyOf(kFlutterSemanticsActionSetText,
494  kFlutterSemanticsActionSetSelection));
495  if (info->action == kFlutterSemanticsActionSetText) {
496  g_autoptr(FlValue) value =
497  decode_semantic_data(info->data, info->data_length);
499  g_free(text);
500  text = g_strdup(fl_value_get_string(value));
501  } else {
502  g_autoptr(FlValue) value =
503  decode_semantic_data(info->data, info->data_length);
506  extent = fl_value_get_int(fl_value_lookup_string(value, "extent"));
507  }
508  return kSuccess;
509  }));
510 
511  g_autoptr(FlAccessibleNode) node =
512  fl_accessible_text_field_new(engine, 123, 1);
513  fl_accessible_node_set_value(node, "Fler");
514 
515  gint pos = 2;
516  atk_editable_text_insert_text(ATK_EDITABLE_TEXT(node), "utt", 3, &pos);
517  EXPECT_EQ(pos, 5);
518  EXPECT_STREQ(text, "Flutter");
519  EXPECT_EQ(base, pos);
520  EXPECT_EQ(extent, pos);
521 
522  atk_editable_text_delete_text(ATK_EDITABLE_TEXT(node), 2, 5);
523  EXPECT_STREQ(text, "Fler");
524  EXPECT_EQ(base, 2);
525  EXPECT_EQ(extent, 2);
526 }
527 
528 // Tests AtkEditableText::copy/cut/paste_text.
529 TEST(FlAccessibleTextFieldTest, CopyCutPasteText) {
530  int base = -1;
531  int extent = -1;
532  FlutterSemanticsAction act = kFlutterSemanticsActionCustomAction;
533 
534  g_autoptr(FlDartProject) project = fl_dart_project_new();
535  g_autoptr(FlEngine) engine = fl_engine_new(project);
536 
537  g_autoptr(GError) error = nullptr;
538  EXPECT_TRUE(fl_engine_start(engine, &error));
539  EXPECT_EQ(error, nullptr);
540 
541  fl_engine_get_embedder_api(engine)->SendSemanticsAction = MOCK_ENGINE_PROC(
542  SendSemanticsAction,
543  ([&act, &base, &extent](auto engine,
544  const FlutterSendSemanticsActionInfo* info) {
545  EXPECT_THAT(info->action,
546  ::testing::AnyOf(kFlutterSemanticsActionCut,
547  kFlutterSemanticsActionCopy,
548  kFlutterSemanticsActionPaste,
549  kFlutterSemanticsActionSetSelection));
550  act = info->action;
551  if (info->action == kFlutterSemanticsActionSetSelection) {
552  g_autoptr(FlValue) value =
553  decode_semantic_data(info->data, info->data_length);
556  extent = fl_value_get_int(fl_value_lookup_string(value, "extent"));
557  }
558  return kSuccess;
559  }));
560 
561  g_autoptr(FlAccessibleNode) node =
562  fl_accessible_text_field_new(engine, 123, 1);
563 
564  atk_editable_text_copy_text(ATK_EDITABLE_TEXT(node), 2, 5);
565  EXPECT_EQ(base, 2);
566  EXPECT_EQ(extent, 5);
567  EXPECT_EQ(act, kFlutterSemanticsActionCopy);
568 
569  atk_editable_text_cut_text(ATK_EDITABLE_TEXT(node), 1, 4);
570  EXPECT_EQ(base, 1);
571  EXPECT_EQ(extent, 4);
572  EXPECT_EQ(act, kFlutterSemanticsActionCut);
573 
574  atk_editable_text_paste_text(ATK_EDITABLE_TEXT(node), 3);
575  EXPECT_EQ(base, 3);
576  EXPECT_EQ(extent, 3);
577  EXPECT_EQ(act, kFlutterSemanticsActionPaste);
578 }
579 
580 TEST(FlAccessibleTextFieldTest, TextBoundary) {
581  g_autoptr(FlDartProject) project = fl_dart_project_new();
582  g_autoptr(FlEngine) engine = fl_engine_new(project);
583  g_autoptr(FlAccessibleNode) node =
584  fl_accessible_text_field_new(engine, 123, 1);
585 
587  "Lorem ipsum.\nDolor sit amet. Praesent commodo?"
588  "\n\nPraesent et felis dui.");
589 
590  // |Lorem
591  gint start_offset = -1, end_offset = -1;
592  g_autofree gchar* lorem_char = atk_text_get_string_at_offset(
593  ATK_TEXT(node), 0, ATK_TEXT_GRANULARITY_CHAR, &start_offset, &end_offset);
594  EXPECT_STREQ(lorem_char, "L");
595  EXPECT_EQ(start_offset, 0);
596  EXPECT_EQ(end_offset, 1);
597 
598  g_autofree gchar* lorem_word = atk_text_get_string_at_offset(
599  ATK_TEXT(node), 0, ATK_TEXT_GRANULARITY_WORD, &start_offset, &end_offset);
600  EXPECT_STREQ(lorem_word, "Lorem");
601  EXPECT_EQ(start_offset, 0);
602  EXPECT_EQ(end_offset, 5);
603 
604  g_autofree gchar* lorem_sentence = atk_text_get_string_at_offset(
605  ATK_TEXT(node), 0, ATK_TEXT_GRANULARITY_SENTENCE, &start_offset,
606  &end_offset);
607  EXPECT_STREQ(lorem_sentence, "Lorem ipsum.");
608  EXPECT_EQ(start_offset, 0);
609  EXPECT_EQ(end_offset, 12);
610 
611  g_autofree gchar* lorem_line = atk_text_get_string_at_offset(
612  ATK_TEXT(node), 0, ATK_TEXT_GRANULARITY_LINE, &start_offset, &end_offset);
613  EXPECT_STREQ(lorem_line, "Lorem ipsum.");
614  EXPECT_EQ(start_offset, 0);
615  EXPECT_EQ(end_offset, 12);
616 
617  g_autofree gchar* lorem_paragraph = atk_text_get_string_at_offset(
618  ATK_TEXT(node), 0, ATK_TEXT_GRANULARITY_PARAGRAPH, &start_offset,
619  &end_offset);
620  EXPECT_STREQ(lorem_paragraph,
621  "Lorem ipsum.\nDolor sit amet. Praesent commodo?");
622  EXPECT_EQ(start_offset, 0);
623  EXPECT_EQ(end_offset, 46);
624 
625  // Pra|esent
626  g_autofree gchar* praesent_char = atk_text_get_string_at_offset(
627  ATK_TEXT(node), 32, ATK_TEXT_GRANULARITY_CHAR, &start_offset,
628  &end_offset);
629  EXPECT_STREQ(praesent_char, "e");
630  EXPECT_EQ(start_offset, 32);
631  EXPECT_EQ(end_offset, 33);
632 
633  g_autofree gchar* praesent_word = atk_text_get_string_at_offset(
634  ATK_TEXT(node), 32, ATK_TEXT_GRANULARITY_WORD, &start_offset,
635  &end_offset);
636  EXPECT_STREQ(praesent_word, "Praesent");
637  EXPECT_EQ(start_offset, 29);
638  EXPECT_EQ(end_offset, 37);
639 
640  g_autofree gchar* praesent_sentence = atk_text_get_string_at_offset(
641  ATK_TEXT(node), 32, ATK_TEXT_GRANULARITY_SENTENCE, &start_offset,
642  &end_offset);
643  EXPECT_STREQ(praesent_sentence, "Praesent commodo?");
644  EXPECT_EQ(start_offset, 29);
645  EXPECT_EQ(end_offset, 46);
646 
647  g_autofree gchar* praesent_line = atk_text_get_string_at_offset(
648  ATK_TEXT(node), 32, ATK_TEXT_GRANULARITY_LINE, &start_offset,
649  &end_offset);
650  EXPECT_STREQ(praesent_line, "Dolor sit amet. Praesent commodo?");
651  EXPECT_EQ(start_offset, 13);
652  EXPECT_EQ(end_offset, 46);
653 
654  g_autofree gchar* praesent_paragraph = atk_text_get_string_at_offset(
655  ATK_TEXT(node), 32, ATK_TEXT_GRANULARITY_PARAGRAPH, &start_offset,
656  &end_offset);
657  EXPECT_STREQ(praesent_paragraph,
658  "Lorem ipsum.\nDolor sit amet. Praesent commodo?");
659  EXPECT_EQ(start_offset, 0);
660  EXPECT_EQ(end_offset, 46);
661 
662  // feli|s
663  g_autofree gchar* felis_char = atk_text_get_string_at_offset(
664  ATK_TEXT(node), 64, ATK_TEXT_GRANULARITY_CHAR, &start_offset,
665  &end_offset);
666  EXPECT_STREQ(felis_char, "s");
667  EXPECT_EQ(start_offset, 64);
668  EXPECT_EQ(end_offset, 65);
669 
670  g_autofree gchar* felis_word = atk_text_get_string_at_offset(
671  ATK_TEXT(node), 64, ATK_TEXT_GRANULARITY_WORD, &start_offset,
672  &end_offset);
673  EXPECT_STREQ(felis_word, "felis");
674  EXPECT_EQ(start_offset, 60);
675  EXPECT_EQ(end_offset, 65);
676 
677  g_autofree gchar* felis_sentence = atk_text_get_string_at_offset(
678  ATK_TEXT(node), 64, ATK_TEXT_GRANULARITY_SENTENCE, &start_offset,
679  &end_offset);
680  EXPECT_STREQ(felis_sentence, "Praesent et felis dui.");
681  EXPECT_EQ(start_offset, 48);
682  EXPECT_EQ(end_offset, 70);
683 
684  g_autofree gchar* felis_line = atk_text_get_string_at_offset(
685  ATK_TEXT(node), 64, ATK_TEXT_GRANULARITY_LINE, &start_offset,
686  &end_offset);
687  EXPECT_STREQ(felis_line, "Praesent et felis dui.");
688  EXPECT_EQ(start_offset, 48);
689  EXPECT_EQ(end_offset, 70);
690 
691  g_autofree gchar* felis_paragraph = atk_text_get_string_at_offset(
692  ATK_TEXT(node), 64, ATK_TEXT_GRANULARITY_PARAGRAPH, &start_offset,
693  &end_offset);
694  EXPECT_STREQ(felis_paragraph, "\nPraesent et felis dui.");
695  EXPECT_EQ(start_offset, 47);
696  EXPECT_EQ(end_offset, 70);
697 }
698 
699 // NOLINTEND(clang-analyzer-core.StackAddressEscape)
void fl_accessible_node_set_text_selection(FlAccessibleNode *self, gint base, gint extent)
void fl_accessible_node_set_actions(FlAccessibleNode *self, FlutterSemanticsAction actions)
void fl_accessible_node_set_value(FlAccessibleNode *self, const gchar *value)
glong glong end
FlAccessibleNode * fl_accessible_text_field_new(FlEngine *engine, FlutterViewId view_id, int32_t id)
static FlValue * decode_semantic_data(const uint8_t *data, size_t data_length)
TEST(FlAccessibleTextFieldTest, SetValue)
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
FlutterEngineProcTable * fl_engine_get_embedder_api(FlEngine *self)
Definition: fl_engine.cc:858
gboolean fl_engine_start(FlEngine *self, GError **error)
Definition: fl_engine.cc:720
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition: fl_engine.cc:691
G_MODULE_EXPORT FlValue * fl_message_codec_decode_message(FlMessageCodec *self, GBytes *message, GError **error)
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
G_MODULE_EXPORT FlStandardMessageCodec * fl_standard_message_codec_new()
G_MODULE_EXPORT FlValue * fl_value_lookup_string(FlValue *self, const gchar *key)
Definition: fl_value.cc:811
G_MODULE_EXPORT int64_t fl_value_get_int(FlValue *self)
Definition: fl_value.cc:668
G_MODULE_EXPORT void fl_value_unref(FlValue *self)
Definition: fl_value.cc:400
G_MODULE_EXPORT FlValueType fl_value_get_type(FlValue *self)
Definition: fl_value.cc:466
G_MODULE_EXPORT FlValue * fl_value_new_bool(bool value)
Definition: fl_value.cc:255
G_MODULE_EXPORT bool fl_value_equal(FlValue *a, FlValue *b)
Definition: fl_value.cc:471
G_MODULE_EXPORT const gchar * fl_value_get_string(FlValue *self)
Definition: fl_value.cc:682
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:42
@ FL_VALUE_TYPE_STRING
Definition: fl_value.h:68
@ FL_VALUE_TYPE_MAP
Definition: fl_value.h:74