Tests for the alert message scroll pane - #2848
Conversation
The scroll pane that 16b5f21 put around the message of an alert came without tests. These cover the two properties it was added for: * a message longer than the cap asks for the cap and not for more, a message shorter than it keeps the height it had, and what does not fit is reachable by scrolling rather than clipped away; * the screen the cap is taken from is the one the owner window stands on, and a window that stands on no screen at all falls back to the primary one. The two helpers are reached by reflection so that the tested code stays the shipped code.
The preferred height of the pane was asked for before it had ever been in a scene, which gave 36 instead of the 4817 the dialog pane sees. The test then laid the pane out at those 36 pixels, where the cap could not possibly bite: taking the cap out of UIFacadeImpl left the test green. Measured after a first layout, and given the height it asks for, it fails as it should.
|
This looks good and the tests pass on my laptop, however, they fail on Github runner because of a slight mismatch in a height: Maybe we can compare a range +- 1 point instead of strict comparison? |
…hem to The cap on the message height is a share of the screen height and is hardly ever whole, while Region rounds the size it hands a child up to the next whole device pixel. A pane that asks for 1024 * 0.6 = 614.4 is given 615.0, which is why the tests pass on a 1920x1080 screen, whose cap of 648.0 is already whole, and fail on a 1280x1024 one. The gap is below one device pixel by construction, so the height comparisons go through two helpers that allow exactly that much. The exact invariants stay strict.
|
Found the cause, and it is neither a font nor a wrapping difference: it is the rounding of The cap is screen.visualBounds.height * 0.6. Your runner's screen is 1280x1024, so the cap
I reproduced your failure verbatim under Xvfb at 1280x1024: "expected: <614.4> but was: Two things follow. First, a +-1 on the comparison in your error message alone would not have made CI green. Second, one pixel is the right number, and it is a bound rather than a guess. The gap is So every height that comes out of a laid-out scene now goes through one of two helpers, What the tolerance costs in sharpness, per assertion, measured at 1280x1024:
The worst of those is 1:581. I checked the tolerance in both directions on each of those assertions separately, at One test I could not exercise: "the cap follows the screen of the owner, not the primary |
In #2833 you said, about testing the three properties of the scroll pane
that 16b5f21 put around the message of an alert:
So here are the other two. Focus traversability is deliberately left out,
as you asked.
This branch adds test code only.
UIFacadeImpl.javais untouched.The height cap (
AlertContentHeightTest)Measured at 1920x1080: the same pane without the cap asks for 4817, with it
for 648, which is 0.6 * 1080.
(33 both ways), which is the "short messages keep the size they have today"
from your commit message, as an assertion.
viewport that is at most the cap high, and scrolling to the end moves it by
exactly the part that did not fit and brings its bottom into the viewport.
Every preferred height is asked for with the content width passed in, since
prefHeight(-1)measures unwrapped text, and only after the pane has been ina scene once, since before
applyCss()the same call answers 36 instead of4817. The uncapped comparison number comes from a second, identically built
and identically laid out
ScrollPanewithout the override, so that bothnumbers arise the same way.
The screen the cap is taken from (
AlertOwnerScreenTest)screenOfreturns the screen a window stands on, checked for every screenthe machine has.
needs more than one screen to say anything, so it is guarded by an
assumption and skips on a single-screen machine.
hypothetical: a
Stagethat has never been shown hasx,y,widthandheightofNaN, andScreen.getScreensForRectangle(NaN, NaN, 1, 1)returns nothing. Without the
orElseinscreenOf, building such an alertthrows.
On the reflection
makeScrollableandscreenOfare private, and nothing outside the alerthas any business calling them, so the tests reach them by reflection rather
than widening them: the tested code stays the shipped code. If you would
rather see them package-private with a comment, say so and I will change it.
Negative controls
Each test was watched failing against a deliberately broken
UIFacadeImpl,then the break was taken back and the green run confirmed:
Math.min(super.computePrefHeight(width), maxHeight)->super.computePrefHeight(width):3 tests fail, e.g.
a long message asks for 4817.0, which is more than the cap of 648.0..orElse(Screen.getPrimary())->.orElseThrow():2 tests fail with
java.util.NoSuchElementException: No value present.screenOf(owner)->Screen.getPrimary(): nothing fails, because themachine these tests were run on has one screen, where the two are the same
function. That is what the skipped assumption above is about. On a
multi-monitor machine that test carries the difference.
Full module run: 96 tests, 0 failures, 1 skipped (the multi-screen one).