defmodule Mv.Membership.Import.ImportRunnerTest do use ExUnit.Case, async: true alias Mv.Membership.Import.ImportRunner describe "carry_groups_forward/2" do test "replaces import_state groups_found with the chunk's grown snapshot" do import_state = %{groups_found: [%{id: "1", name: "A"}]} chunk_result = %{groups_found: [%{id: "1", name: "A"}, %{id: "2", name: "B"}]} assert ImportRunner.carry_groups_forward(import_state, chunk_result) == %{ groups_found: [%{id: "1", name: "A"}, %{id: "2", name: "B"}] } end test "leaves import_state unchanged when the chunk result omits groups_found" do import_state = %{groups_found: [%{id: "1", name: "A"}], other: :kept} chunk_result = %{inserted: 1} assert ImportRunner.carry_groups_forward(import_state, chunk_result) == import_state end end describe "merge_progress/4 warning accumulation" do test "deduplicates identical warnings across chunks instead of growing unbounded" do progress = %{ inserted: 0, failed: 0, errors: [], warnings: ["Fee type 'Ghost' not found; using the default fee type."], status: :running, current_chunk: 0, total_chunks: 3 } chunk_result = %{ inserted: 2, failed: 0, errors: [], errors_truncated?: false, warnings: [ "Fee type 'Ghost' not found; using the default fee type.", "Fee type 'Ghost' not found; using the default fee type." ] } result = ImportRunner.merge_progress(progress, chunk_result, 0) assert result.warnings == ["Fee type 'Ghost' not found; using the default fee type."] end test "preserves distinct warnings while collapsing duplicates" do progress = %{ inserted: 0, failed: 0, errors: [], warnings: ["Fee type 'A' not found; using the default fee type."], status: :running, current_chunk: 0, total_chunks: 2 } chunk_result = %{ inserted: 1, failed: 0, errors: [], errors_truncated?: false, warnings: [ "Fee type 'A' not found; using the default fee type.", "Fee type 'B' not found; using the default fee type." ] } result = ImportRunner.merge_progress(progress, chunk_result, 0) assert result.warnings == [ "Fee type 'A' not found; using the default fee type.", "Fee type 'B' not found; using the default fee type." ] end end describe "read_file_entry/2" do test "returns {:ok, content} for a readable file" do path = Path.join( System.tmp_dir!(), "import_runner_read_#{System.unique_integer([:positive])}.csv" ) File.write!(path, "email;first_name\njohn@example.com;John") on_exit(fn -> File.rm_rf(path) end) assert {:ok, "email;first_name\njohn@example.com;John"} = ImportRunner.read_file_entry(%{path: path}, %{}) end test "returns {:error, message} with a binary message when the file cannot be read" do missing_path = Path.join( System.tmp_dir!(), "import_runner_missing_#{System.unique_integer([:positive])}.csv" ) assert {:error, message} = ImportRunner.read_file_entry(%{path: missing_path}, %{}) assert is_binary(message) assert message != "" end end end