# #region Test.Core.FileIO [C:3] [TYPE Module] [SEMANTICS test,fileio,core]
# @BRIEF Coverage tests for fileio.py missed lines: read/write/archive/retention/yaml/async/consolidate.
# @RELATION BINDS_TO -> [FileIOModule]
# @TEST_EDGE: missing_file -> FileNotFoundError / assertion
# @TEST_EDGE: invalid_type -> InvalidZipFormatError on bad ZIP content
# @TEST_EDGE: external_fail -> OSError on cleanup / permission denied

from datetime import date, timedelta
from pathlib import Path
from unittest.mock import MagicMock, patch
import io
import os
import zipfile

import pytest

from src.core.utils.fileio import (
    InvalidZipFormatError,
    RetentionPolicy,
    _update_yaml_file,
    apply_retention_policy,
    archive_exports,
    asave_and_unpack_dashboard,
    aread_dashboard_from_disk,
    consolidate_archive_folders,
    create_dashboard_export,
    create_temp_file,
    get_filename_from_headers,
    read_dashboard_from_disk,
    remove_empty_directories,
    save_and_unpack_dashboard,
    update_yamls,
    _unzip_to_directory,
)


def _make_zip_bytes(files=None):
    buf = io.BytesIO()
    with zipfile.ZipFile(buf, "w") as zf:
        for name, data in (files or [("f.txt", b"data")]):
            zf.writestr(name, data)
    return buf.getvalue()


# ── create_temp_file: dir cleanup (58-59) + OSError (63-64) ──────────

# #region test_create_temp_dir_cleanup [C:2] [TYPE Function]
# @BRIEF Verify shutil.rmtree cleanup in finally block (lines 58-59).
def test_create_temp_dir_cleanup():
    import tempfile as _tf
    real_td = _tf.TemporaryDirectory
    class PassthroughDir:
        """Context manager that creates a temp dir but does NOT auto-cleanup."""
        def __init__(self, **kw):
            self._d = real_td(**kw)
            self.name = self._d.name
        def __enter__(self):
            return self._d.__enter__()
        def __exit__(self, *a):
            self._d._finalizer.detach()  # prevent auto-cleanup
            self._d._finalizer = None
            return False
    saved = None
    with patch("src.core.utils.fileio.tempfile.TemporaryDirectory", PassthroughDir):
        with create_temp_file(suffix=".dir") as p:
            saved = Path(str(p))
            assert saved.is_dir()
    assert not saved.exists()
# #endregion test_create_temp_dir_cleanup

# #region test_create_temp_cleanup_oserror [C:2] [TYPE Function]
# @BRIEF Verify OSError during cleanup is caught (lines 63-64).
def test_create_temp_cleanup_oserror(monkeypatch):
    orig_unlink = Path.unlink
    def fail_unlink(self):
        raise OSError("permission denied")
    monkeypatch.setattr(Path, "unlink", fail_unlink)
    with create_temp_file(content=b"x", suffix=".txt") as p:
        saved = p
    assert saved.exists()
    orig_unlink(saved)
# #endregion test_create_temp_cleanup_oserror

# ── remove_empty_directories: not-found (76-77) + OSError (84-85) ────

# #region test_remove_empty_dirs_not_found [C:2] [TYPE Function]
# @BRIEF Non-existent directory returns 0 (lines 76-77).
def test_remove_empty_dirs_not_found():
    assert remove_empty_directories("/nonexistent/path/xyz") == 0
# #endregion test_remove_empty_dirs_not_found

# #region test_remove_empty_dirs_oserror [C:2] [TYPE Function]
# @BRIEF OSError during rmdir is caught (lines 84-85).
def test_remove_empty_dirs_oserror(monkeypatch, tmp_path):
    d = tmp_path / "empty"
    d.mkdir()
    monkeypatch.setattr(os, "rmdir", MagicMock(side_effect=OSError("fail")))
    assert remove_empty_directories(str(tmp_path)) == 0
# #endregion test_remove_empty_dirs_oserror

# ── read_dashboard_from_disk (95-102) ─────────────────────────────────

# #region test_read_dashboard_from_disk [C:2] [TYPE Function]
# @BRIEF Reads file content and returns (bytes, name) (lines 95-102).
def test_read_dashboard_from_disk(tmp_path):
    f = tmp_path / "dash.zip"
    f.write_bytes(b"\x00\x01\x02")
    content, name = read_dashboard_from_disk(str(f))
    assert content == b"\x00\x01\x02"
    assert name == "dash.zip"
# #endregion test_read_dashboard_from_disk

# #region test_read_dashboard_empty_file [C:2] [TYPE Function]
# @BRIEF Empty file returns empty bytes (lines 100-101).
def test_read_dashboard_empty_file(tmp_path):
    f = tmp_path / "empty.zip"
    f.write_bytes(b"")
    content, _ = read_dashboard_from_disk(str(f))
    assert content == b""
# #endregion test_read_dashboard_empty_file

# #region test_read_dashboard_not_found [C:2] [TYPE Function]
# @BRIEF Missing file raises AssertionError (line 97).
def test_read_dashboard_not_found():
    with pytest.raises(AssertionError, match="не найден"):
        read_dashboard_from_disk("/no/such/file.zip")
# #endregion test_read_dashboard_not_found

# ── apply_retention_policy (205-229) ──────────────────────────────────

# #region test_apply_retention_policy_buckets [C:2] [TYPE Function]
# @BRIEF Files bucketed into daily/weekly/monthly; too-old excluded (lines 205-229).
def test_apply_retention_policy_buckets(tmp_path, monkeypatch):
    today = date(2025, 6, 1)
    monkeypatch.setattr("src.core.utils.fileio.date", MagicMock(today=MagicMock(return_value=today)))
    files = []
    for days_ago in [1, 3, 10, 20, 60, 120, 400]:
        p = tmp_path / f"f_{days_ago}.zip"
        p.write_bytes(b"x")
        files.append((p, today - timedelta(days=days_ago)))
    policy = RetentionPolicy(daily=7, weekly=4, monthly=12)
    kept = apply_retention_policy(files, policy)
    assert (tmp_path / "f_1.zip") in kept
    assert (tmp_path / "f_3.zip") in kept
    assert (tmp_path / "f_10.zip") in kept
    assert (tmp_path / "f_400.zip") not in kept
# #endregion test_apply_retention_policy_buckets

# ── archive_exports (131-197) ─────────────────────────────────────────

# #region test_archive_exports_no_dir [C:2] [TYPE Function]
# @BRIEF Non-existent dir returns early (lines 133-135).
def test_archive_exports_no_dir():
    archive_exports("/no/such/dir", RetentionPolicy())
# #endregion test_archive_exports_no_dir

# #region test_archive_exports_no_zips [C:2] [TYPE Function]
# @BRIEF Empty dir returns early (lines 140-142).
def test_archive_exports_no_zips(tmp_path):
    archive_exports(str(tmp_path), RetentionPolicy())
# #endregion test_archive_exports_no_zips

# #region test_archive_exports_dedup [C:2] [TYPE Function]
# @BRIEF Deduplication removes older copy; retention cleans the rest (lines 144-197).
def test_archive_exports_dedup(tmp_path):
    z = _make_zip_bytes([("a.txt", b"same")])
    (tmp_path / "old_20250101_120000.zip").write_bytes(z)
    (tmp_path / "new_20250501_120000.zip").write_bytes(z)
    archive_exports(str(tmp_path), RetentionPolicy(daily=365), deduplicate=True)
    remaining = list(tmp_path.glob("*.zip"))
    assert len(remaining) <= 1
# #endregion test_archive_exports_dedup

# ── save_and_unpack_dashboard (237-254) ───────────────────────────────

# #region test_save_and_unpack_basic [C:2] [TYPE Function]
# @BRIEF Save without unpack returns (path, None) (lines 237-251).
def test_save_and_unpack_basic(tmp_path):
    z = _make_zip_bytes()
    zp, out = save_and_unpack_dashboard(z, str(tmp_path / "out"), original_filename="test.zip")
    assert zp.exists() and zp.name == "test.zip"
    assert out is None
# #endregion test_save_and_unpack_basic

# #region test_save_and_unpack_with_unpack [C:2] [TYPE Function]
# @BRIEF Save + unpack extracts files (lines 246-250).
def test_save_and_unpack_with_unpack(tmp_path):
    z = _make_zip_bytes([("inner.txt", b"hello")])
    zp, out = save_and_unpack_dashboard(z, str(tmp_path / "out"), unpack=True)
    assert out is not None
    assert (out / "inner.txt").read_bytes() == b"hello"
# #endregion test_save_and_unpack_with_unpack

# #region test_save_and_unpack_invalid_zip [C:2] [TYPE Function]
# @BRIEF Bad ZIP raises InvalidZipFormatError (lines 252-254).
def test_save_and_unpack_invalid_zip(tmp_path):
    with pytest.raises(InvalidZipFormatError):
        save_and_unpack_dashboard(b"not-a-zip", str(tmp_path), unpack=True)
# #endregion test_save_and_unpack_invalid_zip

# ── update_yamls + _update_yaml_file (263-333) ───────────────────────

# #region test_update_yamls_basic [C:2] [TYPE Function]
# @BRIEF update_yamls iterates YAML files and delegates (lines 263-271).
def test_update_yamls_basic(tmp_path):
    (tmp_path / "a.yaml").write_text("host: old_server\nport: 3306")
    update_yamls(db_configs=[{"old": {"host": "old_server"}, "new": {"host": "new_server"}}], path=str(tmp_path))
    assert "new_server" in (tmp_path / "a.yaml").read_text()
# #endregion test_update_yamls_basic

# #region test_update_yaml_regex [C:2] [TYPE Function]
# @BRIEF Regex replacement in YAML file (lines 287-295).
def test_update_yaml_regex(tmp_path):
    f = tmp_path / "c.yaml"
    f.write_text("value: old_text")
    _update_yaml_file(f, [], r"old_text", "new_text")
    assert "new_text" in f.read_text()
# #endregion test_update_yaml_regex

# #region test_update_yaml_configs [C:2] [TYPE Function]
# @BRIEF Config-based old→new replacement (lines 297-333).
def test_update_yaml_configs(tmp_path):
    f = tmp_path / "d.yaml"
    f.write_text('host: "old_host"\nport: "3306"')
    _update_yaml_file(f, [{"old": {"host": "old_host"}, "new": {"host": "new_host"}}], None, None)
    result = f.read_text()
    assert "new_host" in result
    assert "old_host" not in result
# #endregion test_update_yaml_configs

# #region test_update_yaml_read_error [C:2] [TYPE Function]
# @BRIEF Read error is caught and logged (lines 283-285).
def test_update_yaml_read_error(tmp_path):
    f = tmp_path / "bad.yaml"
    f.write_text("x: 1")
    with patch("builtins.open", side_effect=IOError("fail")):
        _update_yaml_file(f, [], None, None)
# #endregion test_update_yaml_read_error

# #region test_update_yaml_regex_no_change [C:2] [TYPE Function]
# @BRIEF Regex that doesn't match skips rewrite (line 290).
def test_update_yaml_regex_no_change(tmp_path):
    f = tmp_path / "e.yaml"
    f.write_text("value: unchanged")
    _update_yaml_file(f, [], r"NONEXISTENT_PATTERN", "replacement")
    assert f.read_text() == "value: unchanged"
# #endregion test_update_yaml_regex_no_change

# ── consolidate_archive_folders (417, 422, 425-426, 431-432) ─────────

# #region test_consolidate_skip_target [C:2] [TYPE Function]
# @BRIEF source_dir == target_dir hits continue (line 417).
def test_consolidate_skip_target(tmp_path):
    (tmp_path / "sales").mkdir()
    (tmp_path / "sales" / "a.zip").write_bytes(b"z")
    (tmp_path / "sales_2024").mkdir()
    (tmp_path / "sales_2024" / "b.zip").write_bytes(b"z")
    consolidate_archive_folders(tmp_path)
    assert (tmp_path / "sales" / "a.zip").exists()
# #endregion test_consolidate_skip_target

# #region test_consolidate_move_dir [C:2] [TYPE Function]
# @BRIEF shutil.move for subdirectory (line 422).
def test_consolidate_move_dir(tmp_path):
    (tmp_path / "a_1").mkdir()
    (tmp_path / "a_1" / "f.zip").write_bytes(b"z")
    (tmp_path / "a_1" / "sub").mkdir()
    (tmp_path / "a_2").mkdir()
    (tmp_path / "a_2" / "g.zip").write_bytes(b"z")
    consolidate_archive_folders(tmp_path)
    assert (tmp_path / "a").is_dir()
# #endregion test_consolidate_move_dir

# #region test_consolidate_move_error [C:2] [TYPE Function]
# @BRIEF Exception during shutil.move is caught (lines 425-426).
def test_consolidate_move_error(tmp_path):
    (tmp_path / "x_1").mkdir()
    (tmp_path / "x_1" / "f.zip").write_bytes(b"z")
    (tmp_path / "x_1" / "sub").mkdir()
    (tmp_path / "x_2").mkdir()
    (tmp_path / "x_2" / "g.zip").write_bytes(b"z")
    real_move = __import__("shutil").move
    def fail_for_subdir(src, dst):
        if "sub" in str(src):
            raise OSError("move fail")
        return real_move(src, dst)
    with patch("src.core.utils.fileio.shutil.move", side_effect=fail_for_subdir):
        consolidate_archive_folders(tmp_path)
# #endregion test_consolidate_move_error

# #region test_consolidate_rmdir_error [C:2] [TYPE Function]
# @BRIEF Exception during source rmdir is caught (lines 431-432).
def test_consolidate_rmdir_error(tmp_path):
    (tmp_path / "r_1").mkdir()
    (tmp_path / "r_1" / "a.zip").write_bytes(b"z")
    (tmp_path / "r_2").mkdir()
    (tmp_path / "r_2" / "b.zip").write_bytes(b"z")
    (tmp_path / "r_2" / "sub").mkdir()
    (tmp_path / "r_2" / "sub" / "keep.txt").write_text("x")
    real_move = __import__("shutil").move
    def fail_sub(src, dst):
        if "sub" in str(src):
            raise OSError("nope")
        return real_move(src, dst)
    with patch("src.core.utils.fileio.shutil.move", side_effect=fail_sub):
        consolidate_archive_folders(tmp_path)
# #endregion test_consolidate_rmdir_error

# ── aread_dashboard_from_disk (457, 459-460, 464) ────────────────────

# #region test_aread_not_found [C:2] [TYPE Function]
# @BRIEF Missing file raises FileNotFoundError (line 457).
@pytest.mark.asyncio
async def test_aread_not_found():
    with pytest.raises(FileNotFoundError):
        await aread_dashboard_from_disk("/no/such/file.zip")
# #endregion test_aread_not_found

# #region test_aread_large_file_aiofiles [C:2] [TYPE Function]
# @BRIEF File >10MB uses aiofiles path (lines 459-460).
@pytest.mark.asyncio
async def test_aread_large_file_aiofiles(tmp_path):
    from src.core.utils.executors import init_executors, shutdown_executors
    init_executors(file_workers=2)
    try:
        big = tmp_path / "big.zip"
        big.write_bytes(b"A" * (11 * 1024 * 1024))
        content = await aread_dashboard_from_disk(str(big))
        assert len(content) == 11 * 1024 * 1024
    finally:
        shutdown_executors()
# #endregion test_aread_large_file_aiofiles

# #region test_aread_empty_file [C:2] [TYPE Function]
# @BRIEF Empty file triggers warning (line 464).
@pytest.mark.asyncio
async def test_aread_empty_file(tmp_path):
    from src.core.utils.executors import init_executors, shutdown_executors
    init_executors(file_workers=2)
    try:
        f = tmp_path / "empty.zip"
        f.write_bytes(b"")
        content = await aread_dashboard_from_disk(str(f))
        assert content == b""
    finally:
        shutdown_executors()
# #endregion test_aread_empty_file

# ── asave_and_unpack_dashboard (480-508) ──────────────────────────────

# #region test_asave_basic [C:2] [TYPE Function]
# @BRIEF Async save without unpack (lines 480-508).
@pytest.mark.asyncio
async def test_asave_basic(tmp_path):
    from src.core.utils.executors import init_executors, shutdown_executors
    init_executors(file_workers=2)
    try:
        z = _make_zip_bytes()
        zp, out = await asave_and_unpack_dashboard(z, str(tmp_path / "out"), original_filename="a.zip")
        assert zp.exists() and zp.name == "a.zip"
        assert out is None
    finally:
        shutdown_executors()
# #endregion test_asave_basic

# #region test_asave_with_unpack [C:2] [TYPE Function]
# @BRIEF Async save + unpack extracts files (lines 497-507).
@pytest.mark.asyncio
async def test_asave_with_unpack(tmp_path):
    from src.core.utils.executors import init_executors, shutdown_executors
    init_executors(file_workers=2)
    try:
        z = _make_zip_bytes([("inner.txt", b"hello")])
        zp, out = await asave_and_unpack_dashboard(z, str(tmp_path / "out"), unpack=True)
        assert out is not None
        assert (out / "inner.txt").read_bytes() == b"hello"
    finally:
        shutdown_executors()
# #endregion test_asave_with_unpack

# #region test_asave_invalid_zip [C:2] [TYPE Function]
# @BRIEF Invalid ZIP during unpack propagates error (line 500).
@pytest.mark.asyncio
async def test_asave_invalid_zip(tmp_path):
    from src.core.utils.executors import init_executors, shutdown_executors
    init_executors(file_workers=2)
    try:
        with pytest.raises(zipfile.BadZipFile):
            await asave_and_unpack_dashboard(b"bad", str(tmp_path / "out"), unpack=True)
    finally:
        shutdown_executors()
# #endregion test_asave_invalid_zip

# ── _unzip_to_directory (515-516) ─────────────────────────────────────

# #region test_unzip_to_directory [C:2] [TYPE Function]
# @BRIEF Helper extracts ZIP contents (lines 515-516).
def test_unzip_to_directory(tmp_path):
    z = _make_zip_bytes([("a.txt", b"ok")])
    zp = tmp_path / "t.zip"
    zp.write_bytes(z)
    out = tmp_path / "out"
    out.mkdir()
    _unzip_to_directory(str(zp), str(out))
    assert (out / "a.txt").read_bytes() == b"ok"
# #endregion test_unzip_to_directory

# ── Additional edge-case coverage ─────────────────────────────────────

# #region test_create_temp_no_content_branch [C:2] [TYPE Function]
# @BRIEF No-content branch: file created empty, cleanup runs (branch 50->52, line 62).
def test_create_temp_no_content_branch():
    saved = None
    with create_temp_file(suffix=".txt") as p:
        saved = p
        assert p.stat().st_size == 0
    assert not saved.exists()
# #endregion test_create_temp_no_content_branch

# #region test_remove_empty_dirs_success [C:2] [TYPE Function]
# @BRIEF Successful removal increments counter (lines 82-83).
def test_remove_empty_dirs_success(tmp_path):
    (tmp_path / "e1").mkdir()
    (tmp_path / "e2").mkdir()
    (tmp_path / "e2" / "nested").mkdir()
    count = remove_empty_directories(str(tmp_path))
    assert count >= 2
# #endregion test_remove_empty_dirs_success

# #region test_archive_exports_retention_no_dedup [C:2] [TYPE Function]
# @BRIEF Retention without dedup: mtime fallback + old file removed (lines 144→171, 186, 192-197).
def test_archive_exports_retention_no_dedup(tmp_path):
    z = _make_zip_bytes()
    old = tmp_path / "nodate_old.zip"
    old.write_bytes(z)
    old.touch()
    archive_exports(str(tmp_path), RetentionPolicy(daily=0, weekly=0, monthly=0))
# #endregion test_archive_exports_retention_no_dedup

# #region test_archive_exports_dedup_crc_error [C:2] [TYPE Function]
# @BRIEF CRC32 calculation error is caught (lines 160-161).
def test_archive_exports_dedup_crc_error(tmp_path):
    z = _make_zip_bytes()
    (tmp_path / "a_20250501_120000.zip").write_bytes(z)
    with patch("src.core.utils.fileio.calculate_crc32", side_effect=Exception("crc fail")):
        archive_exports(str(tmp_path), RetentionPolicy(daily=365), deduplicate=True)
# #endregion test_archive_exports_dedup_crc_error

# #region test_archive_exports_dedup_unlink_error [C:2] [TYPE Function]
# @BRIEF Duplicate unlink OSError is caught (lines 168-169).
def test_archive_exports_dedup_unlink_error(tmp_path):
    z = _make_zip_bytes()
    (tmp_path / "old_20250101_120000.zip").write_bytes(z)
    (tmp_path / "new_20250501_120000.zip").write_bytes(z)
    real_unlink = Path.unlink
    def fail_old(self):
        if "old_" in str(self):
            raise OSError("unlink fail")
        return real_unlink(self)
    with patch.object(Path, "unlink", fail_old):
        archive_exports(str(tmp_path), RetentionPolicy(daily=365), deduplicate=True)
    assert (tmp_path / "old_20250101_120000.zip").exists()
# #endregion test_archive_exports_dedup_unlink_error

# #region test_archive_exports_invalid_date [C:2] [TYPE Function]
# @BRIEF Invalid date in filename falls back to mtime (lines 181-182).
def test_archive_exports_invalid_date(tmp_path):
    z = _make_zip_bytes()
    (tmp_path / "x_99999999_120000.zip").write_bytes(z)
    archive_exports(str(tmp_path), RetentionPolicy(daily=365), deduplicate=True)
# #endregion test_archive_exports_invalid_date

# #region test_update_yaml_regex_error [C:2] [TYPE Function]
# @BRIEF Invalid regex pattern is caught (lines 294-295).
def test_update_yaml_regex_error(tmp_path):
    f = tmp_path / "bad_re.yaml"
    f.write_text("value: test")
    _update_yaml_file(f, [], r"[invalid(", "replacement")
    assert f.read_text() == "value: test"
# #endregion test_update_yaml_regex_error

# #region test_update_yaml_config_error [C:2] [TYPE Function]
# @BRIEF Config replacement error is caught (lines 332-333).
def test_update_yaml_config_error(tmp_path):
    f = tmp_path / "cfg_err.yaml"
    f.write_text("key: val")
    with patch("re.sub", side_effect=RuntimeError("sub fail")):
        _update_yaml_file(f, [{"old": {"key": "val"}, "new": {"key": "new"}}], None, None)
# #endregion test_update_yaml_config_error

# #region test_consolidate_single_slug [C:2] [TYPE Function]
# @BRIEF Single-dir slug hits continue (line 409).
def test_consolidate_single_slug(tmp_path):
    (tmp_path / "lonely_2024").mkdir()
    (tmp_path / "lonely_2024" / "a.zip").write_bytes(b"z")
    consolidate_archive_folders(tmp_path)
    assert (tmp_path / "lonely_2024").exists()
# #endregion test_consolidate_single_slug

# #region test_acleanup_directory [C:2] [TYPE Function]
# @BRIEF Async directory cleanup via run_blocking (lines 527-528).
@pytest.mark.asyncio
async def test_acleanup_directory(tmp_path):
    from src.core.utils.fileio import acleanup_directory
    from src.core.utils.executors import init_executors, shutdown_executors
    init_executors(file_workers=2)
    try:
        d = tmp_path / "to_clean"
        d.mkdir()
        (d / "f.txt").write_text("x")
        await acleanup_directory(str(d))
        assert not d.exists()
    finally:
        shutdown_executors()
# #endregion test_acleanup_directory

# #region test_aread_bytes_func [C:2] [TYPE Function]
# @BRIEF Async read bytes via run_blocking (lines 538-539).
@pytest.mark.asyncio
async def test_aread_bytes_func(tmp_path):
    from src.core.utils.fileio import aread_bytes
    from src.core.utils.executors import init_executors, shutdown_executors
    init_executors(file_workers=2)
    try:
        f = tmp_path / "data.bin"
        f.write_bytes(b"\xde\xad\xbe\xef")
        result = await aread_bytes(f)
        assert result == b"\xde\xad\xbe\xef"
    finally:
        shutdown_executors()
# #endregion test_aread_bytes_func

# ── create_dashboard_export (341-357) + get_filename_from_headers (374-378) ─

# #region test_create_dashboard_export_basic [C:2] [TYPE Function]
# @BRIEF Creates ZIP from source paths (lines 341-357).
def test_create_dashboard_export_basic(tmp_path):
    src = tmp_path / "src"
    src.mkdir()
    (src / "dash.json").write_text("{}")
    (src / "meta.yaml").write_text("v: 1")
    zp = tmp_path / "export.zip"
    assert create_dashboard_export(zp, [str(src)]) is True
    assert zp.exists()
    with zipfile.ZipFile(zp) as zf:
        assert any("dash.json" in n for n in zf.namelist())
# #endregion test_create_dashboard_export_basic

# #region test_create_dashboard_export_fail [C:2] [TYPE Function]
# @BRIEF Non-existent source returns False (lines 355-357).
def test_create_dashboard_export_fail():
    assert create_dashboard_export("/tmp/x.zip", ["/nonexistent"]) is False
# #endregion test_create_dashboard_export_fail

# #region test_get_filename_from_headers_cov [C:2] [TYPE Function]
# @BRIEF Extracts filename from Content-Disposition header (lines 374-378).
def test_get_filename_from_headers_cov():
    assert get_filename_from_headers({"Content-Disposition": 'attachment; filename="r.pdf"'}) == "r.pdf"
    assert get_filename_from_headers({}) is None
# #endregion test_get_filename_from_headers_cov
# #endregion Test.Core.FileIO
