Consumer Coverage and a11y Flag Wiring#731
Conversation
Adds direct tests for the numeric/scroll/state accessors plus a broad accessor sweep (supported actions, labels, descriptions, set membership, role-derived predicates, values, read-only/disabled composition, and hidden-flag inheritance). Lifts node.rs from 57% to ~97% function coverage.
Adds the Range/WeakRange weak-reference round trip (including the degenerate range and refuse-to-upgrade-against-a-non-text-node cases), the Position page-navigation/document-bound helpers, and the node-level text-selection accessors. Lifts text.rs to ~97% line / ~99% function coverage.
Exercises is_host_focused, focus_in_tree, active_dialog, toolkit_name, toolkit_version, and the update_host_focus_state_and_process_changes path.
Replaces the placeholder page_navigation_resolves_to_document_bounds test, which pinned the degenerate stub behavior, with a real implementation and behavioral tests. Position's page-navigation methods were stubs that resolved every page motion to a document boundary, ignoring the is_page_breaking_object node flag the schema already defines. This wires them to honor real page breaks. Page boundaries are detected from block structure (a Position's text run has an ancestor flagged is_page_breaking_object whose subtree excludes the preceding run), unlike line boundaries (run links) or paragraph boundaries (a run value ending in '\n'). The break is treated as occurring before the flagged node. - is_page_start and the new is_page_end consult the page-break flag. - forward_to_page_start, forward_to_page_end, and backward_to_page_start walk page boundaries, mirroring the paragraph-navigation methods. - A document with no page-break flags is a single page, so behavior is unchanged for every existing provider; only trees that set the flag exercise the new path. The Windows UIA TextUnit_Page mapping inherits this for free; macOS and AT-SPI have no page text granularity and are unaffected.
The CI fmt job (cargo fmt --all -- --check) rejected three spots in the consumer test code: unsorted imports in node.rs, plus an assert_eq! and a use list that rustfmt wraps across lines. Normalize them so the check passes. No behavior change.
A node flagged is_visited (e.g. a hyperlink the user has already followed) now maps to the AT-SPI Visited state. The flag was previously write-only: providers could set it but no adapter read it, so on Unix a visited link was indistinguishable from an unvisited one. - consumer: add Node::is_visited(), matching the sibling flag getters. - atspi-common: insert State::Visited in NodeWrapper::state() alongside the other flag-driven states, with a test covering both directions. State::Visited is the natural target (atspi-common documents it as a hyperlink that has already been activated). Windows has no per-node visited concept; macOS gains one only once objc2-app-kit reaches 0.3 (NSAccessibilityVisitedAttribute), which is gated on the pending objc2 upgrade, so both are left untouched here.
Nodes flagged is_spelling_error / is_grammar_error now surface through
the text-attribute pipeline so assistive technology can announce
misspelled and grammatically incorrect spans. Both flags were
previously write-only: providers could set them but no adapter read
them.
- consumer: treat the flags as inherited text attributes (exposing them
on Range/Position) and split text runs on them.
- AT-SPI: report the "invalid" attribute ("spelling" / "grammar").
- Windows: report the UIA AnnotationTypes attribute (AnnotationType_
SpellingError / GrammarError) as an array, using the reserved "mixed"
value when a flag varies across the range.
The consumer and AT-SPI paths are covered by tests; the Windows arm is
type-checked against the windows-msvc target but relies on CI for
runtime verification, since this was authored without a Windows host.
The macOS adapter is left untouched: its text-attribute path is about to
be reworked by the pending objc2 upgrade (AccessKit#616), so
the marked-misspelled arm is better added on top of that.
|
Hello @William-Selna, thank you for your interest in helping here. Unfortunately this pull request contain too much and barely related changes. Especially important for a first time contributor, please focus on contained changes that will be easier to review. Most of your tests also do too much, prefer smaller unit tests that would be easier to understand if they break. Testing very simple methods for the sake of increasing coverage is not a priority either. When exposing node properties through the platform adapters, remember that Chromium is our reference implementation. Try to handle as much platforms as possible, and link a test program using the accesskit_winit crate to your pull request, so we can at least perform manual testing. I am going to keep this pull request open for now, letting you decide how you want to re-scope it. But I won't review it as is. Thank you for your understanding. |
In this PR
7 commits - I originally planned on purely bumping function test coverage, but I found an odd twist in the wiring and a few stubs from 2022. At first, I intended these to be largely conformance tests (as in look at the asserted behavior), but I was skeptical of the insertion and decided to investigate.
The test I'm referring to is page_navigation_resolves_to_document_bounds(), a test to assert the following 3 position methods:
As was originally written, the test I wrote asserted page-start == page-end == document_end, which appears to me as counterintuitive. So I decided to look further. Pulling up the blame, it appeared as an unwired artifact from 2022. After noticing these stubs, I ran a check I'd written for some of my other projects that flags write-only state, ones settable by a provider, but not read by anything.
The test/grep flagged
is_page_breaking_objectas write-only, which is the exact flag these methods would need to consult. That explains the four stubs below. With nothing reading the flag, they could only ever resolve to document bounds.Open Decision Pending:
is_page_breaking_objectThe schema documents
is_page_breaking_objectonly as "Indicates whether this node causes a page break," and no provider sets it today, so nothing pins down the tree shape a provider is expected to emit. Implementing detection requirescommitting to a contract, and I assumed: A node carrying
is_page_breaking_objectis a container wrapping a page'scontent, and the break occurs before it — so the node's first text-run descendant begins a new page (
starts_new_pagewalks up from a run to find such an ancestor.)Alternatives I did not assume: break-after (the flagged node ends a page), or the flag on a marker/separator node between pages — cf.
is_line_breaking_object, documented as "block level elements, or<br>," which spans both readings.If you intended a different contract, only the detection predicate changes, and the navigation loops and tests are unaffected. The implementation is on the branch if you want it; the contract choice (break-before / break-after / marker-node) is yours, and if you'd rather not commit to page semantics this cycle, the cleanest answer is to drop these commits and keep the rest. I'm also happy to split the PR up, I know the surface is on the larger side.
The Fixes for the Stubs:
forward_to_page_start / forward_to_page_end / backward_to_page_start → the one-line stubs became real loops that walk line-by-line to the next page boundary, structurally identical to the existing paragraph-nav methods.
Wiring other write-only flags.
The same unwired-detector run surfaced more schema flags that were set-able but read by nothing. Three had a real platform home, so this PR wires them:
macOS arms are deferred — its text-attribute path is about to be reworked by the pending objc2 upgrade (#616).
Tests Written to Assert new Behavior
consumer/src/text.rs(13)Page navigation:
is_page_start_tracks_breaks_not_paragraphsforward_to_page_start_skips_intra_page_paragraphsforward_to_page_end_lands_on_page_boundariesbackward_to_page_start_walks_pages_in_reversewithout_page_breaks_navigation_resolves_to_document_boundsSpelling / grammar (auto-generated by
inherited_flags!):is_spelling_error::directly_setis_spelling_error::mixedis_spelling_error::set_on_parentis_spelling_error::unsetis_grammar_error::directly_setis_grammar_error::mixedis_grammar_error::set_on_parentis_grammar_error::unsetplatforms/atspi-common/src/text_attributes.rs(1)invalid_attribute_reflects_error_flagsplatforms/atspi-common/src/node.rs(1)visited_flag_maps_to_atspi_visited_stateOverall accesskit_consumer Coverage improvement
Notes
The Windows AnnotationTypes arm is type-checked against x86_64-pc-windows-msvc but I have no Windows host, so its runtime behavior relies on CI.
I can also split this PR up into just tests or however you like, please don't hesitate to let me know.