| 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"
9 #include "flutter/shell/platform/linux/fl_accessible_text_field.h"
10 #include "flutter/shell/platform/linux/fl_engine_private.h"
11 #include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.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
76 fl_accessible_node_set_value(node, "");
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
97 fl_accessible_node_set_text_selection(node, 2, 3);
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
110 fl_accessible_node_set_text_selection(node, 3, 3);
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
123 fl_accessible_node_set_text_selection(node, 3, 3);
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
136 fl_accessible_node_set_text_selection(node, 4, 4);
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);
159 fl_accessible_node_set_actions(
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
216 fl_accessible_node_set_text_selection(node, 1, 2);
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);
235 EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_MAP);
236 base = fl_value_get_int(fl_value_lookup_string(value, "base"));
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
255 fl_accessible_node_set_text_selection(node, 1, 2);
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");
269 fl_accessible_node_set_text_selection(node, 2, 5);
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
279 fl_accessible_node_set_text_selection(node, 5, 2);
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
287 fl_accessible_node_set_text_selection(node, 5, 5);
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);
308 EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_MAP);
309 base = fl_value_get_int(fl_value_lookup_string(value, "base"));
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
320 fl_accessible_node_set_text_selection(node, 2, 4);
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);
342 EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_MAP);
343 base = fl_value_get_int(fl_value_lookup_string(value, "base"));
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
355 fl_accessible_node_set_text_selection(node, 2, 4);
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);
382 EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_MAP);
383 base = fl_value_get_int(fl_value_lookup_string(value, "base"));
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);
416 EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_STRING);
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);
446 EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_STRING);
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);
452 EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_MAP);
453 base = fl_value_get_int(fl_value_lookup_string(value, "base"));
454 extent =
455 fl_value_get_int(fl_value_lookup_string(value, "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);
498 EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_MAP);
499 base = fl_value_get_int(fl_value_lookup_string(value, "base"));
500 extent =
501 fl_value_get_int(fl_value_lookup_string(value, "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
528 fl_accessible_node_set_value(node,
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:72
fl_engine_get_embedder_api
FlutterEngineProcTable * fl_engine_get_embedder_api(FlEngine *self)
Definition: fl_engine.cc:591
fl_standard_message_codec_new
G_MODULE_EXPORT FlStandardMessageCodec * fl_standard_message_codec_new()
Definition: fl_standard_message_codec.cc:458
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:244
FlValue
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:40
fl_value_lookup_string
G_MODULE_EXPORT FlValue * fl_value_lookup_string(FlValue *self, const gchar *key)
Definition: fl_value.cc:770
fl_value_get_string
const G_MODULE_EXPORT gchar * fl_value_get_string(FlValue *self)
Definition: fl_value.cc:642
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:628
fl_value_unref
G_MODULE_EXPORT void fl_value_unref(FlValue *self)
Definition: fl_value.cc:369
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:428
FL_VALUE_TYPE_STRING
@ FL_VALUE_TYPE_STRING
Definition: fl_value.h:66
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:433
fl_accessible_text_field.h
engine
FlEngine * engine
Definition: fl_view_accessible.cc:29
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:41
node
G_BEGIN_DECLS const FlutterSemanticsNode * node
Definition: fl_view_accessible.h:40
TEST
TEST(FlAccessibleTextFieldTest, SetValue)
Definition: fl_accessible_text_field_test.cc:27