diff options
| author | godosa <godosa@godosa.eu> | 2026-10-07 07:27:17 +0200 |
|---|---|---|
| committer | godosa <godosa@godosa.eu> | 2026-10-07 07:27:17 +0200 |
| commit | 81d4e80fd5aabe4e80f58e960affa795cf7d34ec (patch) | |
| tree | e98eeac2af6af63aa4287bba1f6d4a3af26b5727 /tests/test_migrate.py | |
| download | workflow-81d4e80fd5aabe4e80f58e960affa795cf7d34ec.tar.gz workflow-81d4e80fd5aabe4e80f58e960affa795cf7d34ec.zip | |
workflow: initial public history
Diffstat (limited to 'tests/test_migrate.py')
| -rw-r--r-- | tests/test_migrate.py | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/tests/test_migrate.py b/tests/test_migrate.py new file mode 100644 index 0000000..bd02f92 --- /dev/null +++ b/tests/test_migrate.py @@ -0,0 +1,160 @@ +import sys +import unittest +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) +from wflib import migrate as M +from wflib import tasks as T + +OLD = """\ +# Tasks — demo + +Conventions: CLAUDE.md. + +## Awaiting your decision + +- **Smoke screenshots (need you present)**: windows open hidden, + so screenshots are black. +- Online mod updates (spec step 4) not built. + +## Pending + +1. **[P1] Terrain: cave seams** (Effort: <1h) — close the slit beside the lintel. + - Tests (red first): no edge left open. + - After: Terrain 6/6: cave rendering + sound + Reference: [DESIGN.md#terrain](DESIGN.md#terrain) + +2. N. **[P2] Reputation factions** (Effort: 5h, interactive) (in progress: master; slices 1–2/3 done (see plan)) — make factions friendly. + - Steps: use the table + - nested + - After: Terrain: cave seams + Reference: docs/notes/exe-map.md (ai.c rows), [spec](docs/spec.md#rep). + +3. **[P2] Spirit Powers 3/5: technique keys** (Effort: 1h) — keys 1/2/3. + +4. **[P3] Spirit Powers 4/5: passives. And more** (Effort: 1h) + - After: Spirit Powers 3/5: technique keys + +## Needs human + +Only what a script can't judge. + +1. **[P1] Play-test feel** (Effort: <1h) — last pass 2026-09-13. + - [ ] keyboard works + - [ ] motion smooth + +## Deferred (explicitly out of scope, tracked for later) + +**Final art**: later. +""" + +NEW = """\ +# Tasks — demo + +Conventions: CLAUDE.md. + +## Awaiting your decision + +- **a-smoke-screenshots**: Smoke screenshots (need you present). windows open hidden, + so screenshots are black. + +- **a-online-mod-updates-not-built**: Online mod updates (spec step 4) not built. + +## Pending + +- **t-terrain-cave-seams** [P1] (<1h): Terrain: cave seams. close the slit beside the lintel. + - Tests (red first): no edge left open. + Ref: DESIGN.md#terrain + +- **t-reputation-factions** [P2] (5h, interactive) (in progress: master; slices 1–2/3 done [see plan]): Reputation factions. make factions friendly. + - Steps: use the table + - nested + - After: [[t-terrain-cave-seams]] + Ref: docs/notes/exe-map.md (ai.c rows), docs/spec.md#rep + +- **t-spirit-powers-3** [P2] (1h): Spirit Powers 3/5: technique keys. keys 1/2/3. + +- **t-spirit-powers-4** [P3] (1h): Spirit Powers 4/5: passives, And more. + - After: [[t-spirit-powers-3]] + +## Needs human + +Only what a script can't judge. + +- **t-play-test-feel** [P1] (<1h): Play-test feel. last pass 2026-09-13. + - [ ] keyboard works + - [ ] motion smooth + +## Deferred + +(explicitly out of scope, tracked for later) + +**Final art**: later. +""" + + +class MigrateTest(unittest.TestCase): + def test_converts_all_oddities(self): + new, report = M.migrate(OLD) + self.assertEqual(new, NEW) + self.assertEqual(report.ids, { + "Smoke screenshots (need you present)": "a-smoke-screenshots", + "Online mod updates (spec step 4) not built": "a-online-mod-updates-not-built", + "Terrain: cave seams": "t-terrain-cave-seams", + "Reputation factions": "t-reputation-factions", + "Spirit Powers 3/5: technique keys": "t-spirit-powers-3", + "Spirit Powers 4/5: passives. And more": "t-spirit-powers-4", + "Play-test feel": "t-play-test-feel", + }) + self.assertEqual(report.notes, [ + "t-terrain-cave-seams: dropped 'After: Terrain 6/6: cave rendering + sound' (no open task with that title: done)"]) + + def test_result_parses_clean(self): + doc = T.parse(M.migrate(OLD)[0]) + self.assertEqual([i.error for i in doc.all_items()], [None] * 7) + self.assertEqual(T.render(doc), NEW) + + def test_idempotent(self): + new, report = M.migrate(NEW) + self.assertEqual(new, NEW) + self.assertEqual((report.ids, report.notes), ({}, [])) + + def test_missing_sections_are_added(self): + new, _ = M.migrate("# T\n\n## Pending\n\n1. **[P1] A** (Effort: 1h) — a.\n\n## Notes\n\nprose\n") + self.assertEqual(new, "# T\n\n## Pending\n\n- **t-a** [P1] (1h): A. a.\n\n## Notes\n\nprose\n\n" + "## Awaiting your decision\n\n## Needs human\n\n## Deferred\n") + + def test_same_title_twice_gets_distinct_ids(self): + new, _ = M.migrate("## Pending\n\n1. **[P1] A** (Effort: 1h) — x.\n\n2. **[P1] A** (Effort: 1h) — y.\n") + self.assertIn("- **t-a** [P1] (1h): A. x.", new) + self.assertIn("- **t-a-2** [P1] (1h): A. y.", new) + + def test_ids_avoid_the_archive(self): + new, _ = M.migrate("## Pending\n\n1. **[P1] A** (Effort: 1h) — x.\n", taken={"t-a"}) + self.assertIn("- **t-a-2** [P1] (1h): A. x.", new) + + def test_one_column_deeper_under_a_colon_line_is_a_child(self): + new, _ = M.migrate("## Pending\n\n1. **[P1] A** (Effort: 1h) — x.\n - Seed Qs:\n - first?\n - second?\n" + " - [ ] box\n - [ ] sibling typo\n") + self.assertIn("- **t-a** [P1] (1h): A. x.\n - Seed Qs:\n - first?\n - second?\n" + " - [ ] box\n - [ ] sibling typo\n", new) + + def test_reference_words_that_are_no_path_become_a_note(self): + new, _ = M.migrate("## Pending\n\n1. **[P1] A** (Effort: 1h) — x.\n" + " Reference: docs/a.md (fate rows), skill row notes, src/X.cs, DESIGN.md#terrain\n\n" + "2. **[P1] B** (Effort: 1h) — y.\n Reference: main spec §5\n") + self.assertIn(" Ref: docs/a.md (fate rows; skill row notes), src/X.cs, DESIGN.md#terrain\n", new) + self.assertIn("- **t-b** [P1] (1h): B. y.\n - Reference: main spec §5\n", new) + + def test_reference_note_keeps_the_body_indent(self): + new, _ = M.migrate("## Pending\n\n1. **[P1] A** (Effort: 1h) — x.\n - Steps: s\n Reference: main spec §5\n") + self.assertIn("- **t-a** [P1] (1h): A. x.\n - Steps: s\n - Reference: main spec §5\n", new) + + def test_unreadable_numbered_item_is_reported_and_kept(self): + new, report = M.migrate("## Pending\n\n1. something without the pattern\n body\n") + self.assertIn("1. something without the pattern\n body\n", new) + self.assertEqual(report.notes, ["line 3: numbered item not understood, left as it is: 1. something without the pattern"]) + + +if __name__ == "__main__": + unittest.main() |
