99 lines
4.2 KiB
C
99 lines
4.2 KiB
C
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include "adapter_native.h"
|
|
#include <string.h>
|
|
|
|
static const gchar *content;
|
|
static guint boundaryCalls, characterCalls, textCalls;
|
|
static gboolean failProbe, changedText;
|
|
|
|
guint atspi_text_get_character_at_offset(AtspiText *text, gint offset, GError **error) {
|
|
characterCalls++;
|
|
if (failProbe) {
|
|
g_set_error_literal(error, g_quark_from_static_string("probe"), 1, "removed text");
|
|
return 0;
|
|
}
|
|
return offset >= 0 && offset < g_utf8_strlen(content, -1)
|
|
? g_utf8_get_char(g_utf8_offset_to_pointer(content, offset)) : 0;
|
|
}
|
|
|
|
gint atspi_text_get_character_count(AtspiText *text, GError **error) {
|
|
return g_utf8_strlen(content, -1);
|
|
}
|
|
|
|
gchar *atspi_text_get_text(AtspiText *text, gint start, gint end, GError **error) {
|
|
textCalls++;
|
|
if (changedText) return g_strdup("");
|
|
g_assert_cmpint(start, >=, 0);
|
|
g_assert_cmpint(end - start, <=, 4096);
|
|
g_assert_cmpint(end, <=, g_utf8_strlen(content, -1));
|
|
const gchar *first = g_utf8_offset_to_pointer(content, start);
|
|
return g_strndup(first, g_utf8_offset_to_pointer(content, end) - first);
|
|
}
|
|
|
|
AtspiTextRange *atspi_text_get_string_at_offset(AtspiText *text, gint offset,
|
|
AtspiTextGranularity unit, GError **error) {
|
|
boundaryCalls++;
|
|
// Model the verified browser failure: asking for LINE at the final
|
|
// ellipsis aborts inside the provider, before it can return a bad range.
|
|
if (unit == ATSPI_TEXT_GRANULARITY_LINE && offset >= 0 &&
|
|
offset == g_utf8_strlen(content, -1) - 1) {
|
|
g_assert_cmpuint(g_utf8_get_char(g_utf8_offset_to_pointer(content, offset)), !=, 0x2026);
|
|
}
|
|
AtspiTextRange *range = g_new0(AtspiTextRange, 1);
|
|
range->end_offset = g_utf8_strlen(content, -1);
|
|
range->content = g_strdup(content);
|
|
return range;
|
|
}
|
|
|
|
static void assert_range(const gchar *value, gint offset, AtspiTextGranularity unit,
|
|
gint start, gint end, const gchar *expected, guint calls) {
|
|
content = value;
|
|
boundaryCalls = characterCalls = textCalls = 0;
|
|
GError *error = NULL;
|
|
AtspiTextRange *range = cthulhu_text_get_string_at_offset(NULL, offset, unit, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_nonnull(range);
|
|
g_assert_cmpint(range->start_offset, ==, start);
|
|
g_assert_cmpint(range->end_offset, ==, end);
|
|
g_assert_cmpstr(range->content, ==, expected);
|
|
g_assert_cmpuint(boundaryCalls, ==, calls);
|
|
if (unit != ATSPI_TEXT_GRANULARITY_LINE || offset < 0) g_assert_cmpuint(characterCalls, ==, 0);
|
|
g_assert_cmpuint(textCalls, ==, calls == 0 ? 1 : 0);
|
|
g_free(range->content);
|
|
g_free(range);
|
|
}
|
|
|
|
int main(void) {
|
|
assert_range("Truncated text…", 14, ATSPI_TEXT_GRANULARITY_LINE, 0, 15, "Truncated text…", 0);
|
|
assert_range("…", 0, ATSPI_TEXT_GRANULARITY_LINE, 0, 1, "…", 0);
|
|
assert_range("First\n猫🐈…", 8, ATSPI_TEXT_GRANULARITY_LINE, 6, 9, "猫🐈…", 0);
|
|
assert_range("Ordinary text", 12, ATSPI_TEXT_GRANULARITY_LINE, 0, 13, "Ordinary text", 1);
|
|
assert_range("An… inside", 2, ATSPI_TEXT_GRANULARITY_LINE, 0, 10, "An… inside", 1);
|
|
assert_range("Text…", 4, ATSPI_TEXT_GRANULARITY_CHAR, 0, 5, "Text…", 1);
|
|
assert_range("Text…", 4, ATSPI_TEXT_GRANULARITY_WORD, 0, 5, "Text…", 1);
|
|
assert_range("Text…", -1, ATSPI_TEXT_GRANULARITY_LINE, 0, 5, "Text…", 1);
|
|
gchar *prefix = g_strnfill(5000, 'x');
|
|
gchar *longText = g_strconcat(prefix, "…", NULL);
|
|
assert_range(longText, 5000, ATSPI_TEXT_GRANULARITY_LINE, 905, 5001, longText + 905, 0);
|
|
g_free(prefix);
|
|
g_free(longText);
|
|
|
|
content = "Changed…";
|
|
boundaryCalls = 0;
|
|
changedText = TRUE;
|
|
GError *error = NULL;
|
|
g_assert_null(cthulhu_text_get_string_at_offset(NULL, 7, ATSPI_TEXT_GRANULARITY_LINE, &error));
|
|
g_assert_no_error(error);
|
|
g_assert_cmpuint(boundaryCalls, ==, 0);
|
|
changedText = FALSE;
|
|
failProbe = TRUE;
|
|
g_assert_null(cthulhu_text_get_string_at_offset(NULL, 7, ATSPI_TEXT_GRANULARITY_LINE, &error));
|
|
g_assert_nonnull(error);
|
|
g_assert_cmpuint(boundaryCalls, ==, 0);
|
|
g_clear_error(&error);
|
|
return 0;
|
|
}
|