defmodule BDS.CSM034FileReadBangTest do use ExUnit.Case, async: false import Ecto.Query describe "source-level: no File.read! or File.write! in affected files" do test "preview_assets.ex has no File.read!" do source = File.read!("lib/bds/preview_assets.ex") refute source =~ "File.read!", "preview_assets.ex should use File.read, not File.read!" end test "templates.ex has no File.read!" do source = File.read!("lib/bds/templates.ex") refute source =~ "File.read!", "templates.ex should use File.read, not File.read!" end test "templates.ex has no File.write!" do source = File.read!("lib/bds/templates.ex") refute source =~ "File.write!", "templates.ex should use File.write, not File.write!" end test "release_packaging.ex has no File.read! or File.write!" do source = File.read!("lib/bds/release_packaging.ex") refute source =~ "File.read!", "release_packaging.ex should use File.read, not File.read!" refute source =~ "File.write!", "release_packaging.ex should use File.write, not File.write!" end end describe "preview_assets.generated_outputs/0 handles read errors" do test "returns results for readable files, skips unreadable ones" do outputs = BDS.PreviewAssets.generated_outputs() assert is_list(outputs) assert Enum.all?(outputs, fn {path, body} -> is_binary(path) and is_binary(body) end) end end describe "templates file error handling" do setup do :ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo) temp_dir = Path.join(System.tmp_dir!(), "bds-csm034-#{System.unique_integer([:positive])}") File.mkdir_p!(temp_dir) on_exit(fn -> File.rm_rf(temp_dir) end) {:ok, project} = BDS.Projects.create_project(%{name: "CSM034", data_path: temp_dir}) %{project: project, temp_dir: temp_dir} end test "rebuild skips unreadable template files without crashing", %{ project: project, temp_dir: temp_dir } do templates_dir = Path.join(temp_dir, "templates") File.mkdir_p!(templates_dir) File.write!(Path.join(templates_dir, "good.liquid"), """ --- slug: good kind: post title: Good Template ---
{{ content }}
""") File.write!(Path.join(templates_dir, "bad.liquid"), "no frontmatter here") assert {:ok, templates} = BDS.Templates.rebuild_templates_from_files(project.id) assert length(templates) == 1 assert hd(templates).slug == "good" end test "sync_template_from_file returns error when file is deleted", %{ project: project, temp_dir: temp_dir } do templates_dir = Path.join(temp_dir, "templates") File.mkdir_p!(templates_dir) path = Path.join(templates_dir, "ephemeral.liquid") File.write!(path, """ --- slug: ephemeral kind: post title: Ephemeral ---{{ content }}
""") {:ok, _templates} = BDS.Templates.rebuild_templates_from_files(project.id) template = BDS.Repo.one( from(t in BDS.Templates.Template, where: t.project_id == ^project.id and t.slug == "ephemeral" ) ) File.rm!(path) assert {:error, :not_found} = BDS.Templates.sync_template_from_file(template.id) end test "import_orphan_template_file returns error for missing file", %{project: project} do assert {:error, :not_found} = BDS.Templates.import_orphan_template_file(project.id, "templates/ghost.liquid") end end end