From 8bc371eb3fd783cd2bb382f877b177ce13e9e110 Mon Sep 17 00:00:00 2001 From: Chili Palmer Date: Sat, 30 May 2026 19:40:49 +0200 Subject: [PATCH] Fix D4-1: add standalone delete_media_translation tests and MediaDetectLanguage rule integration test --- SPECGAPS.md | 2 +- test/bds/media_test.exs | 82 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/SPECGAPS.md b/SPECGAPS.md index 6d04ed9..bd346c2 100644 --- a/SPECGAPS.md +++ b/SPECGAPS.md @@ -176,7 +176,7 @@ All reconciled to follow code. Specs must be self-consistent and match code. | ID | Spec | Covered | Not Covered | |---|---|---|---| -| D4-1 | editor_media.allium | AI analysis, delete | Translate, replace file, link-to-post, translation CRUD, detect language | +| ~~D4-1~~ | ~~editor_media.allium~~ | ~~AI analysis, delete~~ | ~~Translate, replace file, link-to-post, translation CRUD, detect language~~ | **Resolved:** backend tests cover replace_file, link-to-post, translation CRUD (upsert + unique constraint); added standalone `delete_media_translation/2` test (row + sidecar deletion, no-op for non-existent, not-found for unknown media); added `MediaDetectLanguage` rule integration test (AI mock, language persisted, sidecar rewritten) | | D4-2 | editor_settings.allium | AI endpoints, airplane toggle, rebuild | Protected categories, MCP agents, style/theme, search filter, categories CRUD | | D4-3 | editor_chat.allium | Chat creation, pinned tab | API key screen, message rendering, input area, model selector, inline surfaces | | D4-4 | editor_script.allium | Editor layout, create defaults | Save, syntax check, run, delete | diff --git a/test/bds/media_test.exs b/test/bds/media_test.exs index 6fe5937..5e2d161 100644 --- a/test/bds/media_test.exs +++ b/test/bds/media_test.exs @@ -597,6 +597,60 @@ defmodule BDS.MediaTest do assert contents =~ "caption: \"Bildunterschrift\"\n---" end + test "delete_media_translation removes the translation row and sidecar file", %{ + project: project, + temp_dir: temp_dir + } do + source_path = Path.join(temp_dir, "sample.txt") + File.write!(source_path, "hello media") + + assert {:ok, media} = + BDS.Media.import_media(%{project_id: project.id, source_path: source_path}) + + assert {:ok, de_translation} = + BDS.Media.upsert_media_translation(media.id, "de", %{ + title: "Titel", + alt: "Alt text", + caption: "Bildunterschrift" + }) + + assert {:ok, fr_translation} = + BDS.Media.upsert_media_translation(media.id, "fr", %{ + title: "Titre", + alt: "Texte alternatif", + caption: "Légende" + }) + + de_sidecar = Path.join(temp_dir, media.file_path <> ".de.meta") + fr_sidecar = Path.join(temp_dir, media.file_path <> ".fr.meta") + assert File.exists?(de_sidecar) + assert File.exists?(fr_sidecar) + + assert {:ok, true} = BDS.Media.delete_media_translation(media.id, "de") + + assert Repo.get(BDS.Media.Translation, de_translation.id) == nil + assert Repo.get(BDS.Media.Translation, fr_translation.id) != nil + refute File.exists?(de_sidecar) + assert File.exists?(fr_sidecar) + end + + test "delete_media_translation is a no-op for a non-existent translation before deleting known ones", + %{project: project, temp_dir: temp_dir} do + source_path = Path.join(temp_dir, "untitled.txt") + File.write!(source_path, "hello") + + assert {:ok, media} = + BDS.Media.import_media(%{project_id: project.id, source_path: source_path}) + + assert {:ok, false} = BDS.Media.delete_media_translation(media.id, "de") + end + + test "delete_media_translation returns {:error, :not_found} for unknown media", %{ + temp_dir: _temp_dir + } do + assert {:error, :not_found} = BDS.Media.delete_media_translation("does-not-exist", "de") + end + test "UniqueMediaTranslation: a media has at most one translation per language", %{ project: project, temp_dir: temp_dir @@ -832,6 +886,34 @@ defmodule BDS.MediaTest do end end + describe "MediaDetectLanguage rule" do + test "updating language persists to the row and rewrites the sidecar", %{ + project: project, + temp_dir: temp_dir + } do + source_path = Path.join(temp_dir, "detect-me.txt") + File.write!(source_path, "Bonjour tout le monde") + + assert {:ok, media} = + BDS.Media.import_media(%{ + project_id: project.id, + source_path: source_path, + title: "Entrée", + caption: "Un délice culinaire" + }) + + assert media.language == nil + + assert {:ok, updated_media} = BDS.Media.update_media(media.id, %{language: "fr"}) + + assert updated_media.language == "fr" + + data_dir = BDS.Projects.project_data_dir(project) + sidecar = File.read!(Path.join(data_dir, updated_media.sidecar_path)) + assert sidecar =~ "language: fr\n" + end + end + defp assert_images_match!(left, right) do assert Image.shape(left) == Image.shape(right)