You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Defer the recursive propagation of suite traits until after filtering (#820)
This PR includes some optimizations to the testing library's planning
logic (in `Runner.Plan`) to avoid unnecessary work in common cases, and
remove unnecessary nodes from the test graph once they're no longer
needed.
### Motivation
The testing library's planning phase includes taking all
runtime-discovered `Test` instances and organizing them into a tree-like
data structure using the internal `Graph` type. It traverses this graph
several times to do things like only run certain tests the user
indicated (by applying a filter), propagate eligible traits from suites
to their children (by recursively applying traits), and implement other
features.
Currently, the step of recursively propagating eligible suite traits to
their children must occur _before_ applying a test filter. This is
because a test filter may require knowledge of trait information --
specifically, the `.tags` and `.hidden` traits. Even though test
filtering only needs these specific traits, the planning phase currently
propagates _all_ recursive suite traits down to _all_ tests, even though
filtering may end up removing the majority of tests from the graph
entirely. This can lead to wasted effort for any tests which were
filtered out, and I anticipate this may become more pronounced in the
future if/when we enhance the trait system to support things like
consolidating same-typed traits with children.
Trait propagation is done by inserting all inherited traits from the
parent at the beginning of the child's trait list (to ensure
deterministic ordering), so this requires shifting the elements in an
array. And this work is only needed if the test filter being applied
includes a query of tests' `.tags` trait. (The `.hidden` trait is
semantically simpler and easier to handle: it's recursive, but it's a
simple Boolean flag which cannot be overridden by children, so it
doesn't need to be "merged" with children.)
There is an opportunity to optimize this flow and completely skip trait
propagation in the common case where a test filter doesn't care about
tags, and allow propagation to happen after the filtering stage.
Additionally, to reduce memory usage and simplify the graph for easier
debugging, the filtering logic could be modified to "prune" the graph by
removing branches which have zero children.
### Modifications
- Add a property to `Configuration.TestFilter` indicating whether the
filter requires knowledge of trait information.
- Consult this property when applying a filter to a test graph. When
necessary, temporarily convert the passed-in graph to a modified graph
and recursively propagate tags to it.
- Modify `Configuration.TestFilter` to prune unnecessary children from
the graph before finishing.
- Modify planning logic in `Runner.Plan` to move the recursive trait
propagation step to after filering.
### Checklist:
- [x] Code and documentation should follow the style of the [Style
Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md).
- [x] If public symbols are renamed or modified, DocC references should
be updated.
0 commit comments