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