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