From 60acda3fee6d300d66b396ddcdd756772bfed375 Mon Sep 17 00:00:00 2001 From: Chili Palmer Date: Sat, 30 May 2026 19:10:40 +0200 Subject: [PATCH] fix: add SidecarRoundtrip tests for D2-6 --- SPECGAPS.md | 2 +- test/bds/media_test.exs | 75 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/SPECGAPS.md b/SPECGAPS.md index 98b38ca..dc21170 100644 --- a/SPECGAPS.md +++ b/SPECGAPS.md @@ -143,7 +143,7 @@ All reconciled to follow code. Specs must be self-consistent and match code. | ~~D2-3~~ | ~~CreateAndPublishScript rule~~ | ~~script.allium:160~~ | **Resolved:** `create_and_publish_script/1` implemented in scripts.ex, 4 tests added (happy path with file assertions + macro entrypoint default + invalid Lua rejection + slug dedup on title conflict) | | ~~D2-4~~ | ~~UniqueScriptSlug dedup~~ | ~~script.allium:115~~ | **Resolved:** test added asserting two scripts with same title produce unique slugs (`dup-slug` → `dup-slug-2`) | | D2-5 | ~~FrontmatterRoundtrip invariant~~ | post.allium:223 | **Resolved:** test added — creates post with all fields, publishes, parses file back via `Frontmatter.parse_document`, asserts every field (id, title, slug, excerpt, status, author, language, doNotTranslate, templateSlug, tags, categories, createdAt, updatedAt, publishedAt, body) matches the published DB record | -| D2-6 | SidecarRoundtrip invariant | media.allium:198 | Write test: write sidecar, read back, assert all fields match | +| ~~D2-6~~ | ~~SidecarRoundtrip invariant~~ | ~~media.allium:198~~ | **Resolved:** 2 tests added — full roundtrip (write sidecar, parse via `Sidecar.parse_document/1`, assert all fields match DB) + nil conditional fields absent from parsed sidecar | | D2-7 | ConditionalPostFields: nil fields absent from frontmatter | frontmatter.allium:398 | Write test: post with nil excerpt/author/language → fields not in file | | D2-8 | ConditionalMediaFields: nil fields absent from sidecar | frontmatter.allium:417 | Write test: media with nil title/alt → fields not in sidecar | | D2-9 | max_posts_per_page 1..500 constraint | metadata.allium:75-77 | Write test: values outside range rejected | diff --git a/test/bds/media_test.exs b/test/bds/media_test.exs index 977744c..0bf6b41 100644 --- a/test/bds/media_test.exs +++ b/test/bds/media_test.exs @@ -642,6 +642,81 @@ defmodule BDS.MediaTest do assert %{language: ["has already been taken"]} = errors_on(changeset) end + test "SidecarRoundtrip: writing then parsing a sidecar yields matching DB metadata", %{ + project: project, + temp_dir: temp_dir + } do + source_path = Path.join(temp_dir, "roundtrip.txt") + File.write!(source_path, "hello media") + + assert {:ok, media} = + BDS.Media.import_media(%{ + project_id: project.id, + source_path: source_path, + title: "Roundtrip Title", + alt: "Roundtrip Alt", + caption: "Roundtrip Caption", + author: "Tester", + language: "en", + tags: ["alpha", "beta"] + }) + + sidecar_path = Path.join(temp_dir, media.sidecar_path) + {:ok, contents} = File.read(sidecar_path) + {:ok, parsed} = BDS.Sidecar.parse_document(contents) + + assert parsed["title"] == media.title + assert parsed["alt"] == media.alt + assert parsed["caption"] == media.caption + assert parsed["tags"] == media.tags + assert parsed["id"] == media.id + assert parsed["originalName"] == media.original_name + assert parsed["mimeType"] == media.mime_type + assert parsed["size"] == media.size + assert parsed["author"] == media.author + assert parsed["language"] == media.language + assert parsed["createdAt"] == media.created_at + assert parsed["updatedAt"] == media.updated_at + end + + test "SidecarRoundtrip: conditional fields are absent from parsed sidecar when nil", %{ + project: project, + temp_dir: temp_dir + } do + source_path = Path.join(temp_dir, "minimal.txt") + File.write!(source_path, "hello media") + + assert {:ok, media} = + BDS.Media.import_media(%{ + project_id: project.id, + source_path: source_path + }) + + assert media.title == nil + assert media.alt == nil + assert media.caption == nil + assert media.author == nil + assert media.language == nil + + sidecar_path = Path.join(temp_dir, media.sidecar_path) + {:ok, contents} = File.read(sidecar_path) + {:ok, parsed} = BDS.Sidecar.parse_document(contents) + + refute Map.has_key?(parsed, "title") + refute Map.has_key?(parsed, "alt") + refute Map.has_key?(parsed, "caption") + refute Map.has_key?(parsed, "author") + refute Map.has_key?(parsed, "language") + + assert Map.has_key?(parsed, "id") + assert Map.has_key?(parsed, "originalName") + assert Map.has_key?(parsed, "mimeType") + assert Map.has_key?(parsed, "size") + assert Map.has_key?(parsed, "tags") + assert Map.has_key?(parsed, "createdAt") + assert Map.has_key?(parsed, "updatedAt") + end + defp errors_on(changeset) do Ecto.Changeset.traverse_errors(changeset, fn {message, opts} -> Regex.replace(~r"%{(\w+)}", message, fn _, key ->