Let a test hold the words the About page shows
FR-DSP-8 asks for a fallback that is *defined*, and a reason that reaches the code but never the screen satisfies half of it. The three readouts are now built by a free function over the survey rather than written straight into the window, so a test can assert that "sRGB assumed" arrives with the reason attached, that an approximated profile says "nearest to" rather than claiming the space, and that the second monitor is described on the page read from the first — which is the display the requirement is actually about. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ Denominators are parsed from [`requirements.md`](requirements.md) at run time, n
|
|||||||
| Metric | Value |
|
| Metric | Value |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Source files scanned | 265 |
|
| Source files scanned | 265 |
|
||||||
| TRACES tags found | 762 |
|
| TRACES tags found | 765 |
|
||||||
| Requirements defined | 177 |
|
| Requirements defined | 177 |
|
||||||
| Requirements covered | 102 |
|
| Requirements covered | 102 |
|
||||||
| **Coverage** | **57.6%** (102/177) |
|
| **Coverage** | **57.6%** (102/177) |
|
||||||
@@ -73,7 +73,7 @@ _None._
|
|||||||
| FR-DSP-1 | [`core/dr-gpu/src/adjust.rs:2088`](../core/dr-gpu/src/adjust.rs#L2088), [`core/dr-gpu/src/adjust.rs:2165`](../core/dr-gpu/src/adjust.rs#L2165), [`core/dr-gpu/src/adjust.rs:2250`](../core/dr-gpu/src/adjust.rs#L2250), [`core/dr-gpu/src/adjust.rs:54`](../core/dr-gpu/src/adjust.rs#L54), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/lib.rs:54`](../core/dr-gpu/src/lib.rs#L54), [`core/dr-gpu/src/lib.rs:94`](../core/dr-gpu/src/lib.rs#L94), [`core/dr-gpu/tests/capture_sharpen.rs:200`](../core/dr-gpu/tests/capture_sharpen.rs#L200), [`core/dr-gpu/tests/detail_stage.rs:328`](../core/dr-gpu/tests/detail_stage.rs#L328), [`core/dr-gpu/tests/local_contrast.rs:263`](../core/dr-gpu/tests/local_contrast.rs#L263), [`core/dr-gpu/tests/noise_reduction.rs:378`](../core/dr-gpu/tests/noise_reduction.rs#L378), [`core/dr-pipeline/src/detail.rs:136`](../core/dr-pipeline/src/detail.rs#L136), [`core/dr-pipeline/src/detail.rs:465`](../core/dr-pipeline/src/detail.rs#L465), [`core/dr-pipeline/src/graph.rs:543`](../core/dr-pipeline/src/graph.rs#L543), [`core/dr-pipeline/src/graph.rs:573`](../core/dr-pipeline/src/graph.rs#L573), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:654`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L654), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/local_contrast.rs:662`](../core/dr-pipeline/src/ops/local_contrast.rs#L662), [`core/dr-pipeline/src/ops/noise_reduction.rs:695`](../core/dr-pipeline/src/ops/noise_reduction.rs#L695), [`core/dr-pipeline/src/spot.rs:673`](../core/dr-pipeline/src/spot.rs#L673), [`ui/dr-ui/src/develop.rs:2668`](../ui/dr-ui/src/develop.rs#L2668), [`ui/dr-ui/src/develop.rs:3694`](../ui/dr-ui/src/develop.rs#L3694), [`ui/dr-ui/src/develop.rs:4177`](../ui/dr-ui/src/develop.rs#L4177), [`ui/dr-ui/src/develop.rs:4211`](../ui/dr-ui/src/develop.rs#L4211), [`ui/dr-ui/src/lib.rs:71`](../ui/dr-ui/src/lib.rs#L71), [`ui/dr-ui/src/lib.rs:737`](../ui/dr-ui/src/lib.rs#L737), [`ui/dr-ui/src/lib.rs:796`](../ui/dr-ui/src/lib.rs#L796) |
|
| FR-DSP-1 | [`core/dr-gpu/src/adjust.rs:2088`](../core/dr-gpu/src/adjust.rs#L2088), [`core/dr-gpu/src/adjust.rs:2165`](../core/dr-gpu/src/adjust.rs#L2165), [`core/dr-gpu/src/adjust.rs:2250`](../core/dr-gpu/src/adjust.rs#L2250), [`core/dr-gpu/src/adjust.rs:54`](../core/dr-gpu/src/adjust.rs#L54), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/lib.rs:54`](../core/dr-gpu/src/lib.rs#L54), [`core/dr-gpu/src/lib.rs:94`](../core/dr-gpu/src/lib.rs#L94), [`core/dr-gpu/tests/capture_sharpen.rs:200`](../core/dr-gpu/tests/capture_sharpen.rs#L200), [`core/dr-gpu/tests/detail_stage.rs:328`](../core/dr-gpu/tests/detail_stage.rs#L328), [`core/dr-gpu/tests/local_contrast.rs:263`](../core/dr-gpu/tests/local_contrast.rs#L263), [`core/dr-gpu/tests/noise_reduction.rs:378`](../core/dr-gpu/tests/noise_reduction.rs#L378), [`core/dr-pipeline/src/detail.rs:136`](../core/dr-pipeline/src/detail.rs#L136), [`core/dr-pipeline/src/detail.rs:465`](../core/dr-pipeline/src/detail.rs#L465), [`core/dr-pipeline/src/graph.rs:543`](../core/dr-pipeline/src/graph.rs#L543), [`core/dr-pipeline/src/graph.rs:573`](../core/dr-pipeline/src/graph.rs#L573), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:654`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L654), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/local_contrast.rs:662`](../core/dr-pipeline/src/ops/local_contrast.rs#L662), [`core/dr-pipeline/src/ops/noise_reduction.rs:695`](../core/dr-pipeline/src/ops/noise_reduction.rs#L695), [`core/dr-pipeline/src/spot.rs:673`](../core/dr-pipeline/src/spot.rs#L673), [`ui/dr-ui/src/develop.rs:2668`](../ui/dr-ui/src/develop.rs#L2668), [`ui/dr-ui/src/develop.rs:3694`](../ui/dr-ui/src/develop.rs#L3694), [`ui/dr-ui/src/develop.rs:4177`](../ui/dr-ui/src/develop.rs#L4177), [`ui/dr-ui/src/develop.rs:4211`](../ui/dr-ui/src/develop.rs#L4211), [`ui/dr-ui/src/lib.rs:71`](../ui/dr-ui/src/lib.rs#L71), [`ui/dr-ui/src/lib.rs:737`](../ui/dr-ui/src/lib.rs#L737), [`ui/dr-ui/src/lib.rs:796`](../ui/dr-ui/src/lib.rs#L796) |
|
||||||
| FR-DSP-6 | [`core/dr-pipeline/src/operation.rs:446`](../core/dr-pipeline/src/operation.rs#L446), [`core/dr-types/src/colour.rs:1`](../core/dr-types/src/colour.rs#L1), [`ui/dr-ui/src/develop.rs:2698`](../ui/dr-ui/src/develop.rs#L2698), [`ui/dr-ui/src/develop.rs:5469`](../ui/dr-ui/src/develop.rs#L5469), [`ui/dr-ui/src/lib.rs:1414`](../ui/dr-ui/src/lib.rs#L1414), [`ui/dr-ui/src/lib.rs:2626`](../ui/dr-ui/src/lib.rs#L2626) |
|
| FR-DSP-6 | [`core/dr-pipeline/src/operation.rs:446`](../core/dr-pipeline/src/operation.rs#L446), [`core/dr-types/src/colour.rs:1`](../core/dr-types/src/colour.rs#L1), [`ui/dr-ui/src/develop.rs:2698`](../ui/dr-ui/src/develop.rs#L2698), [`ui/dr-ui/src/develop.rs:5469`](../ui/dr-ui/src/develop.rs#L5469), [`ui/dr-ui/src/lib.rs:1414`](../ui/dr-ui/src/lib.rs#L1414), [`ui/dr-ui/src/lib.rs:2626`](../ui/dr-ui/src/lib.rs#L2626) |
|
||||||
| FR-DSP-7 | [`core/dr-gpu/src/histogram.rs:147`](../core/dr-gpu/src/histogram.rs#L147), [`core/dr-gpu/src/histogram.rs:1`](../core/dr-gpu/src/histogram.rs#L1), [`core/dr-gpu/src/histogram.rs:281`](../core/dr-gpu/src/histogram.rs#L281), [`core/dr-gpu/src/histogram.rs:50`](../core/dr-gpu/src/histogram.rs#L50), [`core/dr-gpu/src/shaders/histogram.wgsl:1`](../core/dr-gpu/src/shaders/histogram.wgsl#L1), [`ui/dr-ui/src/develop.rs:2747`](../ui/dr-ui/src/develop.rs#L2747), [`ui/dr-ui/src/develop.rs:5279`](../ui/dr-ui/src/develop.rs#L5279), [`ui/dr-ui/src/develop.rs:5311`](../ui/dr-ui/src/develop.rs#L5311), [`ui/dr-ui/src/develop.rs:621`](../ui/dr-ui/src/develop.rs#L621), [`ui/dr-ui/src/histogram.rs:1`](../ui/dr-ui/src/histogram.rs#L1), [`ui/dr-ui/src/lib.rs:1514`](../ui/dr-ui/src/lib.rs#L1514), [`ui/dr-ui/src/lib.rs:297`](../ui/dr-ui/src/lib.rs#L297), [`ui/dr-ui/ui/app.slint:299`](../ui/dr-ui/ui/app.slint#L299), [`ui/dr-ui/ui/histogram.slint:122`](../ui/dr-ui/ui/histogram.slint#L122), [`ui/dr-ui/ui/histogram.slint:1`](../ui/dr-ui/ui/histogram.slint#L1) |
|
| FR-DSP-7 | [`core/dr-gpu/src/histogram.rs:147`](../core/dr-gpu/src/histogram.rs#L147), [`core/dr-gpu/src/histogram.rs:1`](../core/dr-gpu/src/histogram.rs#L1), [`core/dr-gpu/src/histogram.rs:281`](../core/dr-gpu/src/histogram.rs#L281), [`core/dr-gpu/src/histogram.rs:50`](../core/dr-gpu/src/histogram.rs#L50), [`core/dr-gpu/src/shaders/histogram.wgsl:1`](../core/dr-gpu/src/shaders/histogram.wgsl#L1), [`ui/dr-ui/src/develop.rs:2747`](../ui/dr-ui/src/develop.rs#L2747), [`ui/dr-ui/src/develop.rs:5279`](../ui/dr-ui/src/develop.rs#L5279), [`ui/dr-ui/src/develop.rs:5311`](../ui/dr-ui/src/develop.rs#L5311), [`ui/dr-ui/src/develop.rs:621`](../ui/dr-ui/src/develop.rs#L621), [`ui/dr-ui/src/histogram.rs:1`](../ui/dr-ui/src/histogram.rs#L1), [`ui/dr-ui/src/lib.rs:1514`](../ui/dr-ui/src/lib.rs#L1514), [`ui/dr-ui/src/lib.rs:297`](../ui/dr-ui/src/lib.rs#L297), [`ui/dr-ui/ui/app.slint:299`](../ui/dr-ui/ui/app.slint#L299), [`ui/dr-ui/ui/histogram.slint:122`](../ui/dr-ui/ui/histogram.slint#L122), [`ui/dr-ui/ui/histogram.slint:1`](../ui/dr-ui/ui/histogram.slint#L1) |
|
||||||
| FR-DSP-8 | [`platform/dr-plat/src/display.rs:1`](../platform/dr-plat/src/display.rs#L1), [`platform/dr-plat/src/display/icc.rs:1`](../platform/dr-plat/src/display/icc.rs#L1), [`platform/dr-plat/src/display/wayland.rs:1`](../platform/dr-plat/src/display/wayland.rs#L1), [`platform/dr-plat/src/display/x11.rs:1`](../platform/dr-plat/src/display/x11.rs#L1), [`ui/dr-ui/src/develop.rs:2644`](../ui/dr-ui/src/develop.rs#L2644), [`ui/dr-ui/src/develop.rs:2698`](../ui/dr-ui/src/develop.rs#L2698), [`ui/dr-ui/src/develop.rs:5469`](../ui/dr-ui/src/develop.rs#L5469), [`ui/dr-ui/src/develop.rs:5515`](../ui/dr-ui/src/develop.rs#L5515), [`ui/dr-ui/src/develop.rs:5534`](../ui/dr-ui/src/develop.rs#L5534), [`ui/dr-ui/src/develop.rs:689`](../ui/dr-ui/src/develop.rs#L689), [`ui/dr-ui/src/display_ui.rs:1`](../ui/dr-ui/src/display_ui.rs#L1), [`ui/dr-ui/src/display_ui.rs:258`](../ui/dr-ui/src/display_ui.rs#L258), [`ui/dr-ui/src/lib.rs:1388`](../ui/dr-ui/src/lib.rs#L1388), [`ui/dr-ui/src/lib.rs:1414`](../ui/dr-ui/src/lib.rs#L1414), [`ui/dr-ui/src/lib.rs:2603`](../ui/dr-ui/src/lib.rs#L2603), [`ui/dr-ui/src/lib.rs:2626`](../ui/dr-ui/src/lib.rs#L2626), [`ui/dr-ui/ui/app.slint:1708`](../ui/dr-ui/ui/app.slint#L1708), [`ui/dr-ui/ui/app.slint:278`](../ui/dr-ui/ui/app.slint#L278), [`ui/dr-ui/ui/settings.slint:120`](../ui/dr-ui/ui/settings.slint#L120), [`ui/dr-ui/ui/settings.slint:730`](../ui/dr-ui/ui/settings.slint#L730) |
|
| FR-DSP-8 | [`platform/dr-plat/src/display.rs:1`](../platform/dr-plat/src/display.rs#L1), [`platform/dr-plat/src/display/icc.rs:1`](../platform/dr-plat/src/display/icc.rs#L1), [`platform/dr-plat/src/display/wayland.rs:1`](../platform/dr-plat/src/display/wayland.rs#L1), [`platform/dr-plat/src/display/x11.rs:1`](../platform/dr-plat/src/display/x11.rs#L1), [`ui/dr-ui/src/develop.rs:2644`](../ui/dr-ui/src/develop.rs#L2644), [`ui/dr-ui/src/develop.rs:2698`](../ui/dr-ui/src/develop.rs#L2698), [`ui/dr-ui/src/develop.rs:5469`](../ui/dr-ui/src/develop.rs#L5469), [`ui/dr-ui/src/develop.rs:5515`](../ui/dr-ui/src/develop.rs#L5515), [`ui/dr-ui/src/develop.rs:5534`](../ui/dr-ui/src/develop.rs#L5534), [`ui/dr-ui/src/develop.rs:689`](../ui/dr-ui/src/develop.rs#L689), [`ui/dr-ui/src/display_ui.rs:192`](../ui/dr-ui/src/display_ui.rs#L192), [`ui/dr-ui/src/display_ui.rs:1`](../ui/dr-ui/src/display_ui.rs#L1), [`ui/dr-ui/src/display_ui.rs:325`](../ui/dr-ui/src/display_ui.rs#L325), [`ui/dr-ui/src/display_ui.rs:346`](../ui/dr-ui/src/display_ui.rs#L346), [`ui/dr-ui/src/display_ui.rs:379`](../ui/dr-ui/src/display_ui.rs#L379), [`ui/dr-ui/src/lib.rs:1388`](../ui/dr-ui/src/lib.rs#L1388), [`ui/dr-ui/src/lib.rs:1414`](../ui/dr-ui/src/lib.rs#L1414), [`ui/dr-ui/src/lib.rs:2603`](../ui/dr-ui/src/lib.rs#L2603), [`ui/dr-ui/src/lib.rs:2626`](../ui/dr-ui/src/lib.rs#L2626), [`ui/dr-ui/ui/app.slint:1708`](../ui/dr-ui/ui/app.slint#L1708), [`ui/dr-ui/ui/app.slint:278`](../ui/dr-ui/ui/app.slint#L278), [`ui/dr-ui/ui/settings.slint:120`](../ui/dr-ui/ui/settings.slint#L120), [`ui/dr-ui/ui/settings.slint:730`](../ui/dr-ui/ui/settings.slint#L730) |
|
||||||
| FR-EXP-1 | [`core/dr-export/src/encode.rs:1`](../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) |
|
| FR-EXP-1 | [`core/dr-export/src/encode.rs:1`](../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) |
|
||||||
| FR-EXP-2 | [`core/dr-export/src/encode.rs:1`](../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/error.rs:26`](../core/dr-export/src/error.rs#L26), [`core/dr-export/src/icc.rs:1`](../core/dr-export/src/icc.rs#L1), [`core/dr-export/src/lib.rs:153`](../core/dr-export/src/lib.rs#L153), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/lib.rs:53`](../core/dr-export/src/lib.rs#L53), [`core/dr-gpu/src/adjust.rs:2398`](../core/dr-gpu/src/adjust.rs#L2398), [`core/dr-pipeline/src/graph.rs:533`](../core/dr-pipeline/src/graph.rs#L533), [`core/dr-pipeline/src/graph.rs:587`](../core/dr-pipeline/src/graph.rs#L587), [`core/dr-pipeline/src/operation.rs:446`](../core/dr-pipeline/src/operation.rs#L446), [`core/dr-types/src/colour.rs:1`](../core/dr-types/src/colour.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`core/dr-types/src/settings.rs:595`](../core/dr-types/src/settings.rs#L595), [`ui/dr-ui/src/develop.rs:5534`](../ui/dr-ui/src/develop.rs#L5534), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) |
|
| FR-EXP-2 | [`core/dr-export/src/encode.rs:1`](../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/error.rs:26`](../core/dr-export/src/error.rs#L26), [`core/dr-export/src/icc.rs:1`](../core/dr-export/src/icc.rs#L1), [`core/dr-export/src/lib.rs:153`](../core/dr-export/src/lib.rs#L153), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/lib.rs:53`](../core/dr-export/src/lib.rs#L53), [`core/dr-gpu/src/adjust.rs:2398`](../core/dr-gpu/src/adjust.rs#L2398), [`core/dr-pipeline/src/graph.rs:533`](../core/dr-pipeline/src/graph.rs#L533), [`core/dr-pipeline/src/graph.rs:587`](../core/dr-pipeline/src/graph.rs#L587), [`core/dr-pipeline/src/operation.rs:446`](../core/dr-pipeline/src/operation.rs#L446), [`core/dr-types/src/colour.rs:1`](../core/dr-types/src/colour.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`core/dr-types/src/settings.rs:595`](../core/dr-types/src/settings.rs#L595), [`ui/dr-ui/src/develop.rs:5534`](../ui/dr-ui/src/develop.rs#L5534), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) |
|
||||||
| FR-EXP-3 | [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/size.rs:1`](../core/dr-export/src/size.rs#L1), [`core/dr-export/src/size.rs:25`](../core/dr-export/src/size.rs#L25), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) |
|
| FR-EXP-3 | [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/size.rs:1`](../core/dr-export/src/size.rs#L1), [`core/dr-export/src/size.rs:25`](../core/dr-export/src/size.rs#L25), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) |
|
||||||
|
|||||||
+146
-25
@@ -142,32 +142,14 @@ impl DisplayWatch {
|
|||||||
physical(self.logical_canvas.get(), window.window().scale_factor())
|
physical(self.logical_canvas.get(), window.window().scale_factor())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push the three About-page readouts.
|
/// Push the About-page readouts.
|
||||||
fn publish(&self, window: &AppWindow) {
|
fn publish(&self, window: &AppWindow) {
|
||||||
let survey = self.survey.borrow();
|
let Some(readouts) = readouts(&self.survey.borrow(), self.current.get()) else {
|
||||||
let index = self.current.get();
|
return;
|
||||||
let here = survey
|
};
|
||||||
.displays
|
window.set_display_name(readouts.name.into());
|
||||||
.get(index)
|
window.set_display_colour(readouts.colour.into());
|
||||||
.or_else(|| survey.displays.first());
|
window.set_display_others(readouts.others.into());
|
||||||
let Some(here) = here else { return };
|
|
||||||
|
|
||||||
window.set_display_name(format!("{} ({})", here.name, survey.server.label()).into());
|
|
||||||
window.set_display_colour(here.profile.describe().into());
|
|
||||||
|
|
||||||
// The other monitors, listed rather than hidden. FR-DSP-8 is a
|
|
||||||
// multi-monitor requirement and the failure it names — the second
|
|
||||||
// display showing wrong colours — is invisible from the first, so a
|
|
||||||
// page that described only the display it was being read on would
|
|
||||||
// report nothing about the case that matters.
|
|
||||||
let others: Vec<String> = survey
|
|
||||||
.displays
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter(|(i, _)| *i != index)
|
|
||||||
.map(|(_, d)| format!("{}: {}", d.name, d.profile.describe()))
|
|
||||||
.collect();
|
|
||||||
window.set_display_others(others.join(" · ").into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Re-ask the platform and re-resolve which display is showing the canvas.
|
/// Re-ask the platform and re-resolve which display is showing the canvas.
|
||||||
@@ -200,6 +182,55 @@ impl DisplayWatch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The three strings the About page shows about the session's colour path.
|
||||||
|
pub(crate) struct Readouts {
|
||||||
|
pub name: String,
|
||||||
|
pub colour: String,
|
||||||
|
pub others: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TRACES: FR-DSP-8
|
||||||
|
/// Turn a survey into what the About page says.
|
||||||
|
///
|
||||||
|
/// A free function over the survey rather than a method that writes into the
|
||||||
|
/// window, because the requirement's visibility clause is the part worth
|
||||||
|
/// asserting: FR-DSP-8 asks for a fallback that is *defined*, and a reason
|
||||||
|
/// that reaches the code but never the screen satisfies half of that. This is
|
||||||
|
/// where a test can hold the strings.
|
||||||
|
///
|
||||||
|
/// `None` only for a survey with no displays at all, which `probe` does not
|
||||||
|
/// produce.
|
||||||
|
pub(crate) fn readouts(survey: &DisplaySurvey, index: usize) -> Option<Readouts> {
|
||||||
|
// Clamped rather than indexed: a monitor unplugged between the survey and
|
||||||
|
// this call leaves an index pointing past the end, and the page must
|
||||||
|
// describe *a* display rather than nothing.
|
||||||
|
let index = if index < survey.displays.len() {
|
||||||
|
index
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
let here = survey.displays.get(index)?;
|
||||||
|
|
||||||
|
// The other monitors, listed rather than hidden. FR-DSP-8 is a
|
||||||
|
// multi-monitor requirement and the failure it names — the second display
|
||||||
|
// showing wrong colours — is invisible from the first, so a page that
|
||||||
|
// described only the display it was being read on would report nothing
|
||||||
|
// about the case that matters.
|
||||||
|
let others: Vec<String> = survey
|
||||||
|
.displays
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(i, _)| *i != index)
|
||||||
|
.map(|(_, d)| format!("{}: {}", d.name, d.profile.describe()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Some(Readouts {
|
||||||
|
name: format!("{} ({})", here.name, survey.server.label()),
|
||||||
|
colour: here.profile.describe(),
|
||||||
|
others: others.join(" · "),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Start following the window's display, and answer once immediately.
|
/// Start following the window's display, and answer once immediately.
|
||||||
///
|
///
|
||||||
/// `redraw` is the window's ordinary re-render, so a display change costs
|
/// `redraw` is the window's ordinary re-render, so a display change costs
|
||||||
@@ -254,6 +285,96 @@ pub(crate) fn attach(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use dr_plat::{Bounds, DisplayInfo, DisplayProfile, DisplayServer, FallbackReason};
|
||||||
|
|
||||||
|
fn two_monitors() -> DisplaySurvey {
|
||||||
|
DisplaySurvey {
|
||||||
|
server: DisplayServer::X11,
|
||||||
|
displays: vec![
|
||||||
|
DisplayInfo {
|
||||||
|
name: "eDP-1".to_string(),
|
||||||
|
bounds: Some(Bounds {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 1920,
|
||||||
|
height: 1200,
|
||||||
|
}),
|
||||||
|
profile: DisplayProfile::fallback(FallbackReason::NoWaylandProtocol),
|
||||||
|
},
|
||||||
|
DisplayInfo {
|
||||||
|
name: "DP-2".to_string(),
|
||||||
|
bounds: Some(Bounds {
|
||||||
|
x: 1920,
|
||||||
|
y: 0,
|
||||||
|
width: 2560,
|
||||||
|
height: 1440,
|
||||||
|
}),
|
||||||
|
profile: DisplayProfile {
|
||||||
|
space: dr_types::ColourSpace::DisplayP3,
|
||||||
|
source: dr_plat::ProfileSource::X11RootProperty(
|
||||||
|
"_ICC_PROFILE_1".to_string(),
|
||||||
|
),
|
||||||
|
described_as: Some("EIZO CG279X".to_string()),
|
||||||
|
approximated: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TRACES: FR-DSP-8
|
||||||
|
/// The fallback is defined *and visible*, which is what the requirement
|
||||||
|
/// asks for and the half that is easy to leave out.
|
||||||
|
#[test]
|
||||||
|
fn the_about_page_says_which_acquisition_path_the_session_is_on() {
|
||||||
|
let survey = two_monitors();
|
||||||
|
let shown = readouts(&survey, 0).expect("a display");
|
||||||
|
|
||||||
|
assert!(shown.name.contains("eDP-1"), "{}", shown.name);
|
||||||
|
assert!(shown.name.contains("X11"), "{}", shown.name);
|
||||||
|
// A photographer being shown sRGB because the compositor would not say
|
||||||
|
// otherwise must be able to find that out rather than wonder.
|
||||||
|
assert!(shown.colour.contains("sRGB"), "{}", shown.colour);
|
||||||
|
assert!(shown.colour.contains("assumed"), "{}", shown.colour);
|
||||||
|
assert!(
|
||||||
|
shown.colour.contains("colour management"),
|
||||||
|
"the reason for the fallback did not reach the page: {}",
|
||||||
|
shown.colour
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TRACES: FR-DSP-8
|
||||||
|
/// The second monitor is described on the page read on the first.
|
||||||
|
///
|
||||||
|
/// The requirement's whole subject is the display the reader is *not*
|
||||||
|
/// looking at: "showing wrong colours on the second display is a
|
||||||
|
/// correctness defect". A page that listed only the current one would say
|
||||||
|
/// nothing about the case it exists for.
|
||||||
|
#[test]
|
||||||
|
fn the_other_monitor_is_named_on_the_page_read_from_this_one() {
|
||||||
|
let survey = two_monitors();
|
||||||
|
let shown = readouts(&survey, 0).expect("a display");
|
||||||
|
assert!(shown.others.contains("DP-2"), "{}", shown.others);
|
||||||
|
assert!(shown.others.contains("Display P3"), "{}", shown.others);
|
||||||
|
// Approximated, and saying so. An honest approximation the user can
|
||||||
|
// see is the whole trade made in `dr_plat::display`.
|
||||||
|
assert!(shown.others.contains("nearest to"), "{}", shown.others);
|
||||||
|
assert!(shown.others.contains("EIZO CG279X"), "{}", shown.others);
|
||||||
|
|
||||||
|
// And from the second monitor's point of view, the first is the other.
|
||||||
|
let shown = readouts(&survey, 1).expect("a display");
|
||||||
|
assert!(shown.colour.contains("Display P3"), "{}", shown.colour);
|
||||||
|
assert!(shown.others.contains("eDP-1"), "{}", shown.others);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A single-monitor desktop leaves the row empty rather than repeating
|
||||||
|
/// itself, which is what makes the row conditional in `settings.slint`.
|
||||||
|
#[test]
|
||||||
|
fn one_display_has_no_others_to_list() {
|
||||||
|
let survey = DisplaySurvey::assumed_srgb(FallbackReason::NoWaylandProtocol);
|
||||||
|
let shown = readouts(&survey, 0).expect("a display");
|
||||||
|
assert!(shown.others.is_empty(), "{}", shown.others);
|
||||||
|
}
|
||||||
|
|
||||||
/// TRACES: FR-DSP-8
|
/// TRACES: FR-DSP-8
|
||||||
/// Fractional scaling renders more pixels, not the same pixels stretched.
|
/// Fractional scaling renders more pixels, not the same pixels stretched.
|
||||||
|
|||||||
Reference in New Issue
Block a user