mirror of
https://github.com/devmobasa/wayscriber.git
synced 2026-11-01 07:36:42 +01:00
test(config): pin config.example.toml values to the compiled defaults
The example claims every value in it is a configured default, but the guard tests only checked key presence, never values - and three drifts had already accumulated: the example and docs shipped clear_preset_1..5 as empty while the code binds Ctrl+1..5, head_at_end as false while the code defaults true, and the docs' arrow "Defaults" list still said 30.0 degrees for an angle the code sharpened to 24.0. The new test parses the example, serializes it next to Config::default(), and diffs the trees path by path. Legitimate differences are allowlisted with their reasons: env-dependent page navigation, and sections that spell out effective built-in defaults for fields whose compiled default is "unset" (boards, quick colors, the sample preset slot, toolbar order).
This commit is contained in:
1 parent
7b02e96721
commit
d81161c83e
3 files changed
+94
-14
No files matched your search
+6
-6
@@ -296,11 +296,11 @@ save_preset_2 = ["Shift+2"]
|
||||
save_preset_3 = ["Shift+3"]
|
||||
save_preset_4 = ["Shift+4"]
|
||||
save_preset_5 = ["Shift+5"]
|
||||
clear_preset_1 = []
|
||||
clear_preset_2 = []
|
||||
clear_preset_3 = []
|
||||
clear_preset_4 = []
|
||||
clear_preset_5 = []
|
||||
clear_preset_1 = ["Ctrl+1"]
|
||||
clear_preset_2 = ["Ctrl+2"]
|
||||
clear_preset_3 = ["Ctrl+3"]
|
||||
clear_preset_4 = ["Ctrl+4"]
|
||||
clear_preset_5 = ["Ctrl+5"]
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────────────────
|
||||
# Keybinding Examples
|
||||
@@ -1287,7 +1287,7 @@ length = 20.0
|
||||
angle_degrees = 24.0
|
||||
|
||||
# Place the arrowhead at the end of the line instead of the start
|
||||
head_at_end = false
|
||||
head_at_end = true
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# PERFORMANCE SETTINGS
|
||||
|
||||
+8
-8
@@ -392,13 +392,13 @@ length = 20.0
|
||||
angle_degrees = 24.0
|
||||
|
||||
# Place the arrowhead at the end of the line instead of the start
|
||||
head_at_end = false
|
||||
head_at_end = true
|
||||
```
|
||||
|
||||
**Defaults:**
|
||||
- Length: 20.0px
|
||||
- Angle: 30.0°
|
||||
- Head at end: false (head at the start)
|
||||
- Angle: 24.0°
|
||||
- Head at end: true
|
||||
|
||||
### `[presets]` - Quick Tool Slots
|
||||
|
||||
@@ -1877,11 +1877,11 @@ save_preset_2 = ["Shift+2"]
|
||||
save_preset_3 = ["Shift+3"]
|
||||
save_preset_4 = ["Shift+4"]
|
||||
save_preset_5 = ["Shift+5"]
|
||||
clear_preset_1 = []
|
||||
clear_preset_2 = []
|
||||
clear_preset_3 = []
|
||||
clear_preset_4 = []
|
||||
clear_preset_5 = []
|
||||
clear_preset_1 = ["Ctrl+1"]
|
||||
clear_preset_2 = ["Ctrl+2"]
|
||||
clear_preset_3 = ["Ctrl+3"]
|
||||
clear_preset_4 = ["Ctrl+4"]
|
||||
clear_preset_5 = ["Ctrl+5"]
|
||||
|
||||
# Help overlay (press F10 while drawing for a full reference)
|
||||
```
|
||||
|
||||
@@ -526,6 +526,86 @@ fn save_with_backup_preserves_symlinked_config_target_and_backup_contents() {
|
||||
});
|
||||
}
|
||||
|
||||
/// Every value in `config.example.toml` claims to be a configured default.
|
||||
/// This pins that claim: the example parsed as a `Config` must serialize to
|
||||
/// the same tree as `Config::default()`, so a default changed in code without
|
||||
/// updating the example (or vice versa) fails here instead of drifting.
|
||||
#[test]
|
||||
fn config_example_values_equal_the_compiled_defaults() {
|
||||
// Values with a documented reason to differ:
|
||||
// - page navigation consults the desktop environment at call time; the
|
||||
// example documents the non-GNOME variant.
|
||||
// - boards.items, drawing.quick_colors, presets.slot_1, and the toolbar
|
||||
// order lists spell out effective built-in defaults for fields whose
|
||||
// compiled default is "unset" (or, for boards, author colors in the
|
||||
// friendlier `{ rgb = ... }` syntax that serializes differently).
|
||||
// boards.items also hides a known internal inconsistency: the serde
|
||||
// field default for auto_adjust_pen is true while the hand-built
|
||||
// transparent default is false.
|
||||
const ALLOWED_DRIFT: &[&str] = &[
|
||||
"keybindings.page_prev",
|
||||
"keybindings.page_next",
|
||||
"boards.items",
|
||||
"drawing.quick_colors",
|
||||
"presets.slot_1",
|
||||
"ui.toolbar.items.order",
|
||||
];
|
||||
|
||||
let example = include_str!("../../../config.example.toml");
|
||||
let example: Config = toml::from_str(example).expect("config.example.toml should parse");
|
||||
let example = toml::Value::try_from(example).expect("serialize example config");
|
||||
let defaults = toml::Value::try_from(Config::default()).expect("serialize default config");
|
||||
|
||||
let mut drifts = Vec::new();
|
||||
collect_value_drifts("", &example, &defaults, &mut drifts);
|
||||
drifts.retain(|entry| {
|
||||
!ALLOWED_DRIFT
|
||||
.iter()
|
||||
.any(|allowed| entry.starts_with(allowed))
|
||||
});
|
||||
assert!(
|
||||
drifts.is_empty(),
|
||||
"config.example.toml drifted from Config::default():\n{}",
|
||||
drifts.join("\n")
|
||||
);
|
||||
}
|
||||
|
||||
fn collect_value_drifts(
|
||||
path: &str,
|
||||
example: &toml::Value,
|
||||
defaults: &toml::Value,
|
||||
drifts: &mut Vec<String>,
|
||||
) {
|
||||
match (example, defaults) {
|
||||
(toml::Value::Table(example), toml::Value::Table(defaults)) => {
|
||||
let missing = defaults.keys().filter(|key| !example.contains_key(*key));
|
||||
for key in example.keys().chain(missing) {
|
||||
let child = if path.is_empty() {
|
||||
key.clone()
|
||||
} else {
|
||||
format!("{path}.{key}")
|
||||
};
|
||||
match (example.get(key), defaults.get(key)) {
|
||||
(Some(example), Some(defaults)) => {
|
||||
collect_value_drifts(&child, example, defaults, drifts)
|
||||
}
|
||||
(Some(example), None) => {
|
||||
drifts.push(format!("{child}: example has {example}, defaults omit it"))
|
||||
}
|
||||
(None, Some(defaults)) => drifts.push(format!(
|
||||
"{child}: defaults have {defaults}, example omits it"
|
||||
)),
|
||||
(None, None) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
(example, defaults) if example == defaults => {}
|
||||
(example, defaults) => {
|
||||
drifts.push(format!("{path}: example {example} vs default {defaults}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_example_parses_and_documents_current_user_facing_fields() {
|
||||
let example = include_str!("../../../config.example.toml");
|
||||
|
||||
Reference in new issue
Block a user