Add headless regression tests for Prop Editor functionality
- Implement tests for PropFile, including preset conversion, file dictionary conversion, round-trip serialization, version rejection, default values for missing keys, flattening, sanitization, and save/load functionality. - Create tests for PropEditor, covering window title formatting, mode button text, safe saving, and recent file list management. - Add tests for PropTheme, validating fallback behavior, invalid input handling, and default values for primitives and UI tokens. - Introduce tests for ThumbnailCache, ensuring proper key formatting, PNG handling, and behavior with missing files.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
# Phase 9 Prop Editor — Round 5 (File → Recent + save-serialization fix)
|
||||
|
||||
Status: **implemented** (2026-09-19; direct bugfix + feature round).
|
||||
|
||||
Source: two user feedback points against the shipped Round 4 Prop Editor.
|
||||
|
||||
## Feedback summary
|
||||
|
||||
1. File → Recent: show the last 5 opened props (sandbox-stage pattern).
|
||||
2. Loading `props/eye.prop` draws nothing (the prop name shows, geometry is blank).
|
||||
|
||||
## Diagnosis (point 2 — root cause)
|
||||
|
||||
`PropFile._serialize_shape()` declared
|
||||
|
||||
```gdscript
|
||||
var points: PackedVector2Array = shape.get("points", PackedVector2Array())
|
||||
```
|
||||
|
||||
but the editor always serializes **export-format** shapes whose `points` is an `Array` of
|
||||
`{x, y}` dictionaries. The implicit `Array → PackedVector2Array` conversion cannot construct
|
||||
`Vector2` from a dictionary and **silently yields `Vector2.ZERO` per element**, preserving the
|
||||
count but zeroing every coordinate. Every save therefore wrote all points as `(0, 0)` —
|
||||
verified in `props/eye.prop` and `props/box.prop` (all `x: 0.0, y: 0.0`), which load as a
|
||||
degenerate, invisible shape. The round-1 tests only asserted point *counts* and dict *shape*,
|
||||
so the corruption slipped through.
|
||||
|
||||
**Fix:** `_serialize_shape()` now uses the existing `_coerce_points()` helper (which handles
|
||||
both `PackedVector2Array` and `Array`-of-`{x,y}` inputs). Regression assertions were added so
|
||||
point **values** are verified through `to_file_dict` and the full round-trip.
|
||||
|
||||
The two already-saved user files (`props/eye.prop`, `props/box.prop`) are unrecoverable
|
||||
(every coordinate was zeroed at save time) and must be re-authored.
|
||||
|
||||
## Changes
|
||||
|
||||
| Target | Change |
|
||||
| --- | --- |
|
||||
| `scripts/prop_file.gd` | `_serialize_shape` uses `_coerce_points` (bug fix). |
|
||||
| `scripts/prop_editor.gd` | `SETTINGS_PATH := "user://prop_editor_settings.json"`, `RECENT_MAX := 5`, `_recent_props`; `update_recent_list(list, path, max)` static (dedupe + front-insert + trim); 🕑 Recent submenu in the File menu (`RecentProps` child popup, updated on `about_to_popup`, missing files pruned, "(No recent props)" placeholder); `_load_settings`/`_save_settings`; `_push_recent(path)` on every successful load; missing recent → error dialog + removal. |
|
||||
| `tests/test_prop_editor_file.gd` | New value-preservation assertions (serialized `x == 64`, round-trip `(64,0)`/`(64,64)`). |
|
||||
| `tests/test_prop_editor_round3.gd` | New `_test_recent_list` (dedupe, front-insert, trim). |
|
||||
|
||||
## Verification
|
||||
|
||||
- `--check-only` clean; all five suites green: file 66, theme 53, canvas 87, thumb 10, round3 21.
|
||||
- Manual F6: save a prop with shapes at distinct coordinates, reload — geometry must match;
|
||||
File → 🕑 Recent lists the last 5 opens and opens them; missing recent file shows the error
|
||||
and prunes itself.
|
||||
Reference in New Issue
Block a user