import ast
import re
import sys
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import patch

from dirty_equals import IsStr

from inline_snapshot import external
from inline_snapshot import outsource
from inline_snapshot import snapshot
from inline_snapshot._external._external_location import ExternalLocation
from inline_snapshot._external._find_external import ensure_import
from inline_snapshot._external._find_external import used_externals_in
from inline_snapshot._global_state import snapshot_env
from inline_snapshot.extra import raises
from inline_snapshot.testing import Example

from ..conftest import check_update
from ..utils import apply_changes


def test_basic():
    check_update(
        "assert outsource('text') == snapshot()",
        flags="create",
        expected_code="""\
from inline_snapshot import external
assert outsource('text') == snapshot(external("uuid:f728b4fa-4248-4e3a-8a5d-2f346baa9455.txt"))\
""",
    )


# def test_external():
#     assert repr(external("11111111112222222222.txt")) == snapshot(
#         'external("111111111122*.txt")'
#     )


def test_outsource():

    Example("""\
from inline_snapshot import outsource, snapshot,external,register_format_alias

register_format_alias(".log",".txt")

def test_a():
    assert outsource("test") == external()

    assert outsource("test", suffix=".log") == external()

    assert outsource(b"test") == external()
""").run_pytest(
        ["--inline-snapshot=create"],
        changed_files=snapshot(
            {
                ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
                "tests/__inline_snapshot__/test_something/test_a/e3e70682-c209-4cac-a29f-6fbed82c07cd.txt": "test",
                "tests/__inline_snapshot__/test_something/test_a/eb1167b3-67a9-4378-bc65-c1e582e2e662.bin": "test",
                "tests/__inline_snapshot__/test_something/test_a/f728b4fa-4248-4e3a-8a5d-2f346baa9455.log": "test",
                "tests/test_something.py": """\
from inline_snapshot import outsource, snapshot,external,register_format_alias

register_format_alias(".log",".txt")

def test_a():
    assert outsource("test") == external("uuid:e3e70682-c209-4cac-a29f-6fbed82c07cd.txt")

    assert outsource("test", suffix=".log") == external("uuid:f728b4fa-4248-4e3a-8a5d-2f346baa9455.log")

    assert outsource(b"test") == external("uuid:eb1167b3-67a9-4378-bc65-c1e582e2e662.bin")
""",
            }
        ),
        returncode=1,
        outcomes={"passed": 1, "errors": 1},
    ).run_pytest(["--inline-snapshot=disable"])


def test_compare_outsource():
    with snapshot_env():
        assert outsource("one") == outsource("one")
        assert outsource("one") != outsource("two")


def test_hash_collision():
    e = (
        Example(
            {
                "pyproject.toml": """\
[tool.inline-snapshot]
default-storage="hash"
""",
                "tests/test_a.py": """
from inline_snapshot import outsource,snapshot,external

def test_a():
    assert outsource("test4") == snapshot()
    assert outsource("test5") == snapshot()
    assert outsource("test6") == snapshot()
    if False:
        assert outsource("test4") == external("hash:a*.txt")
""",
            }
        )
        .run_inline(
            ["--inline-snapshot=create"],
            changed_files=snapshot(
                {
                    ".inline-snapshot/external/a140c0c1eda2def2b830363ba362aa4d7d255c262960544821f556e16661b6ff.txt": "test5",
                    ".inline-snapshot/external/a4e624d686e03ed2767c0abd85c14426b0b1157d2ce81d27bb4fe4f6f01d688a.txt": "test4",
                    ".inline-snapshot/external/ed0cb90bdfa4f93981a7d03cff99213a86aa96a6cbcf89ec5e8889871f088727.txt": "test6",
                    ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_a.py
""",
                    "tests/test_a.py": """\

from inline_snapshot import outsource,snapshot,external

def test_a():
    assert outsource("test4") == snapshot(external("hash:a4e624d686e0*.txt"))
    assert outsource("test5") == snapshot(external("hash:a140c0c1eda2*.txt"))
    assert outsource("test6") == snapshot(external("hash:ed0cb90bdfa4*.txt"))
    if False:
        assert outsource("test4") == external("hash:a*.txt")
""",
                }
            ),
        )
        .replace("False", "True")
    )

    e.run_inline(
        raises="StorageLookupError: hash collision files=['a140c0c1eda2def2b830363ba362aa4d7d255c262960544821f556e16661b6ff.txt', 'a4e624d686e03ed2767c0abd85c14426b0b1157d2ce81d27bb4fe4f6f01d688a.txt']"
    )


def test_hash_not_found():
    with raises(
        snapshot(
            "StorageLookupError: hash 'bbbbb*.txt' is not found in the HashStorage"
        )
    ):
        with snapshot_env():
            assert outsource("test4") == external("hash:bbbbb*.txt")


def test_update_legacy_external_names():
    (
        Example(
            {
                "pyproject.toml": """\
[tool.inline-snapshot]
default-storage="hash"
""",
                "tests/test_something.py": """\
from inline_snapshot import outsource,snapshot

def test_something():
    assert outsource("foo") == snapshot()
""",
            }
        )
        .run_pytest(
            ["--inline-snapshot=create"],
            changed_files=snapshot(
                {
                    ".inline-snapshot/external/2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae.txt": "foo",
                    ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
                    "tests/test_something.py": """\
from inline_snapshot import outsource,snapshot

from inline_snapshot import external

def test_something():
    assert outsource("foo") == snapshot(external("hash:2c26b46b68ff*.txt"))
""",
                }
            ),
            returncode=1,
            outcomes={"passed": 1, "errors": 1},
        )
        .run_inline(reported_categories=snapshot(None))
        .change_code(lambda code: code.replace("hash:", ""))
        .run_inline(reported_categories=snapshot({"update"}))
        .run_inline(
            ["--inline-snapshot=update"],
            reported_categories=snapshot(None),
            changed_files=snapshot({"tests/test_something.py": """\
from inline_snapshot import outsource,snapshot

from inline_snapshot import external

def test_something():
    assert outsource("foo") == snapshot(external("hash:2c26b46b68ff*.txt"))
"""}),
        )
    )


def test_pytest_compare_external():
    Example("""\
from inline_snapshot import external, snapshot, outsource

def test_a():
    s=snapshot()
    assert outsource("test") == s

    assert outsource("test2") == s
        """).run_pytest(
        ["--inline-snapshot=create"],
        returncode=1,
        error="""\
>       assert outsource("test2") == s
E       AssertionError: assert Outsourced(data='test2', suffix=None, storage=None) == 'test'
E        +  where Outsourced(data='test2', suffix=None, storage=None) = outsource('test2')
""",
        changed_files={
            ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
            "tests/__inline_snapshot__/test_something/test_a/f728b4fa-4248-4e3a-8a5d-2f346baa9455.txt": "test",
            "tests/test_something.py": """\
from inline_snapshot import external, snapshot, outsource

def test_a():
    s=snapshot(external("uuid:f728b4fa-4248-4e3a-8a5d-2f346baa9455.txt"))
    assert outsource("test") == s

    assert outsource("test2") == s
        \
""",
        },
        outcomes={"failed": 1, "errors": 1},
    ).run_pytest(
        [],
        error=snapshot("""\
>       assert outsource("test2") == s
E       AssertionError: assert 'test2' == 'test'
E         \n\
E         - test
E         + test2
E         ?     +
"""),
        returncode=1,
        outcomes={"failed": 1, "errors": 1},
    )


def test_pytest_compare_external_bytes():
    Example("""\
from inline_snapshot import external, snapshot, outsource

def test_a():
    s=snapshot()
    assert outsource(b"test") == s

    assert outsource(b"test2") == s
        """).run_pytest(
        ["--inline-snapshot=create"],
        error=(
            snapshot("""\
>       assert outsource(b"test2") == s
E       AssertionError: assert Outsourced(data=b'test2', suffix=None, storage=None) == b'test'
E        +  where Outsourced(data=b'test2', suffix=None, storage=None) = outsource(b'test2')
""")
            if sys.version_info >= (3, 11)
            else snapshot("""\
>       assert outsource(b"test2") == s
E       AssertionError
""")
        ),
        returncode=1,
        changed_files={
            ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
            "tests/__inline_snapshot__/test_something/test_a/f728b4fa-4248-4e3a-8a5d-2f346baa9455.bin": "test",
            "tests/test_something.py": """\
from inline_snapshot import external, snapshot, outsource

def test_a():
    s=snapshot(external("uuid:f728b4fa-4248-4e3a-8a5d-2f346baa9455.bin"))
    assert outsource(b"test") == s

    assert outsource(b"test2") == s
        \
""",
        },
        outcomes={"failed": 1, "errors": 1},
    )


def test_pytest_existing_external_import():
    Example("""\
from inline_snapshot import external, snapshot, outsource

def test_a():
    assert outsource("test") == snapshot()
""").run_pytest(
        ["--inline-snapshot=create"],
        changed_files=snapshot(
            {
                ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
                "tests/__inline_snapshot__/test_something/test_a/f728b4fa-4248-4e3a-8a5d-2f346baa9455.txt": "test",
                "tests/test_something.py": """\
from inline_snapshot import external, snapshot, outsource

def test_a():
    assert outsource("test") == snapshot(external("uuid:f728b4fa-4248-4e3a-8a5d-2f346baa9455.txt"))
""",
            }
        ),
        returncode=1,
        outcomes={"passed": 1, "errors": 1},
    )


def test_pytest_trim_external():
    e = (
        Example(
            {
                "pyproject.toml": """\
[tool.inline-snapshot]
default-storage="hash"
""",
                "tests/test_a.py": """\
from inline_snapshot import outsource, snapshot

def test_a():
    assert outsource("test") == snapshot()

    # split

    assert outsource("test2") == snapshot()
        """,
            }
        )
        .run_pytest(
            ["--inline-snapshot=create"],
            changed_files=snapshot(
                {
                    ".inline-snapshot/external/60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752.txt": "test2",
                    ".inline-snapshot/external/9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08.txt": "test",
                    ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_a.py
""",
                    "tests/test_a.py": """\
from inline_snapshot import outsource, snapshot

from inline_snapshot import external

def test_a():
    assert outsource("test") == snapshot(external("hash:9f86d081884c*.txt"))

    # split

    assert outsource("test2") == snapshot(external("hash:60303ae22b99*.txt"))
        \
""",
                }
            ),
            returncode=1,
            outcomes={"passed": 1, "errors": 1},
        )
        .change_code(lambda code: code.split("# split")[0])
    )

    e.run_pytest([], report=snapshot(""))

    e.run_pytest(
        ["--inline-snapshot=trim"],
        changed_files=snapshot(
            {
                ".inline-snapshot/external/60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752.txt": None
            }
        ),
    )


def test_pytest_new_external():
    Example(
        {
            "pyproject.toml": """\
[tool.inline-snapshot]
default-storage="hash"
""",
            "tests/test_a.py": """\
from inline_snapshot import outsource, snapshot

def test_a():
    assert outsource("test") == snapshot()
""",
        }
    ).run_pytest(
        [],
        changed_files=snapshot({}),
        returncode=1,
        outcomes={"passed": 1, "errors": 1},
    ).run_pytest(
        ["--inline-snapshot=create"],
        changed_files=snapshot(
            {
                ".inline-snapshot/external/9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08.txt": "test",
                ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_a.py
""",
                "tests/test_a.py": """\
from inline_snapshot import outsource, snapshot

from inline_snapshot import external

def test_a():
    assert outsource("test") == snapshot(external("hash:9f86d081884c*.txt"))
""",
            }
        ),
        returncode=1,
        outcomes={"passed": 1, "errors": 1},
    )


def test_pytest_config_hash_length():
    Example(
        {
            "pyproject.toml": """\
[tool.inline-snapshot]
default-storage="hash"
hash-length=5
""",
            "tests/test_a.py": """\
from inline_snapshot import outsource, snapshot

def test_a():
    assert outsource("test") == snapshot()
""",
        }
    ).run_pytest(
        ["--inline-snapshot=create"],
        changed_files=snapshot(
            {
                ".inline-snapshot/external/9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08.txt": "test",
                ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_a.py
""",
                "tests/test_a.py": """\
from inline_snapshot import outsource, snapshot

from inline_snapshot import external

def test_a():
    assert outsource("test") == snapshot(external("hash:9f86d*.txt"))
""",
            }
        ),
        returncode=1,
        outcomes={"passed": 1, "errors": 1},
    )


def test_errors():
    with raises(snapshot("ValueError: suffix has to start with a '.' like '.png'")):
        with snapshot_env():
            outsource("test", suffix="blub")

    with raises(
        snapshot(
            "UsageError: No format handler found for the given type 'test_errors.<locals>.C'."
        )
    ):

        class C: ...

        with snapshot_env():
            outsource(C())

    with raises(snapshot("ValueError: 'invalid' is missing a suffix")):
        with snapshot_env():
            external("invalid")


def test_uses_external():
    assert used_externals_in(
        Path("a.py"), ast.parse("[external('hash:111*.txt')]"), check_import=False
    ) == snapshot(
        [
            ExternalLocation(
                storage="hash",
                stem="111*",
                suffix=".txt",
                filename=Path("a.py"),
                linenumber=1,
            )
        ]
    )
    assert not used_externals_in(
        Path("a.py"), ast.parse("[external()]"), check_import=False
    )
    assert not used_externals_in(
        Path("a.py"), ast.parse("[external]"), check_import=False
    )
    assert used_externals_in(
        Path("a.py"), ast.parse("[external('hash:111*.txt')]"), check_import=True
    ) == snapshot([])


def test_read_external_source_files_ignores_special_lines():
    Example(
        {
            "tests/test_something.py": """\
from inline_snapshot import external

def test_invalid_external_source_files():
    assert "hello" == external()
""",
        }
    ).run_inline(
        ["--inline-snapshot=create"],
        changed_files={
            ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
            "tests/__inline_snapshot__/test_something/test_invalid_external_source_files/e3e70682-c209-4cac-a29f-6fbed82c07cd.txt": "hello",
            "tests/test_something.py": """\
from inline_snapshot import external

def test_invalid_external_source_files():
    assert "hello" == external("uuid:e3e70682-c209-4cac-a29f-6fbed82c07cd.txt")
""",
        },
    ).change_code(
        lambda s: """
>>>>>> start
====== blub
<<<<<< bar
# comment
file_does_not_exist.py
""" + s,
        filename=".inline-snapshot/files_using_external.txt",
    ).run_inline(
        changed_files={".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
"""}
    )


def test_write_external_source_files_falls_back_to_absolute_path():
    def relpath_raises(path, start):
        raise ValueError

    Example(
        {
            "tests/test_something.py": """\
from inline_snapshot import external

def test_x():
    assert "hello" == external()
""",
        }
    ).run_inline(
        ["--inline-snapshot=create"],
        context_managers=[
            patch(
                "inline_snapshot._external._tracked_files.os",
                SimpleNamespace(path=SimpleNamespace(relpath=relpath_raises)),
            )
        ],
        changed_files={
            ".inline-snapshot/files_using_external.txt": IsStr(
                regex=r"#.*\n.*/tests/test_something\.py\n"
            ),
            "tests/__inline_snapshot__/test_something/test_x/e3e70682-c209-4cac-a29f-6fbed82c07cd.txt": "hello",
            "tests/test_something.py": """\
from inline_snapshot import external

def test_x():
    assert "hello" == external("uuid:e3e70682-c209-4cac-a29f-6fbed82c07cd.txt")
""",
        },
    )


def test_remove_external():
    Example(
        {
            "tests/test_something.py": """\
from inline_snapshot import external

def test_x():
    assert "hello" == external()
""",
        }
    ).run_inline(
        ["--inline-snapshot=create"],
        changed_files={
            ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
            "tests/__inline_snapshot__/test_something/test_x/e3e70682-c209-4cac-a29f-6fbed82c07cd.txt": "hello",
            "tests/test_something.py": """\
from inline_snapshot import external

def test_x():
    assert "hello" == external("uuid:e3e70682-c209-4cac-a29f-6fbed82c07cd.txt")
""",
        },
    ).change_code(
        lambda code: re.sub("assert.*external(.*)", "pass", code)
    ).run_inline(
        ["--inline-snapshot=trim"],
        reported_categories=set(),
        changed_files={
            ".inline-snapshot/files_using_external.txt": None,
            "tests/__inline_snapshot__/test_something/test_x/e3e70682-c209-4cac-a29f-6fbed82c07cd.txt": None,
        },
    )


def test_no_imports():
    Example("""\
def test_something():
    from inline_snapshot import outsource,snapshot
    assert outsource("test") == snapshot()
""").run_pytest(
        ["--inline-snapshot=create"],
        outcomes=snapshot({"passed": 1, "errors": 1}),
        changed_files=snapshot(
            {
                ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
                "tests/__inline_snapshot__/test_something/test_something/f728b4fa-4248-4e3a-8a5d-2f346baa9455.txt": "test",
                "tests/test_something.py": """\

from inline_snapshot import external
def test_something():
    from inline_snapshot import outsource,snapshot
    assert outsource("test") == snapshot(external("uuid:f728b4fa-4248-4e3a-8a5d-2f346baa9455.txt"))
""",
            }
        ),
        returncode=snapshot(1),
    )


def test_ensure_imports(tmp_path):
    file = tmp_path / "file.py"
    file.write_bytes(b"""\
from os import environ
from os import getcwd
""")

    with apply_changes() as recorder:
        ensure_import(file, {"os": ["chdir", "environ"]}, set(), recorder)

    assert file.read_text("utf-8") == snapshot("""\
from os import environ
from os import getcwd

from os import chdir
""")


def test_ensure_imports_with_comment(tmp_path):
    file = tmp_path / "file.py"
    file.write_bytes(b"""\
from os import environ # comment
""")

    with apply_changes() as recorder:
        ensure_import(file, {"os": ["chdir"]}, set(), recorder)

    assert file.read_text("utf-8") == snapshot("""\
from os import environ # comment

from os import chdir
""")


def test_ensure_imports_with_docstring(tmp_path):
    file = tmp_path / "file.py"
    file.write_bytes(b"""\
''' docstring '''
from __future__ import annotations
""")

    with apply_changes() as recorder:
        ensure_import(file, {"os": ["chdir"]}, set(), recorder)

    assert file.read_text("utf-8") == snapshot("""\
''' docstring '''
from __future__ import annotations

from os import chdir
""")


def test_new_externals():
    Example(
        {
            "pyproject.toml": """\
[tool.inline-snapshot]
default-storage="hash"
""",
            "tests/test_something.py": """\
from inline_snapshot import outsource, snapshot


def test_something():
    outsource("blub")

    assert outsource("foo") == snapshot()

    """,
        }
    ).run_pytest(
        ["--inline-snapshot=create"],
        changed_files=snapshot(
            {
                ".inline-snapshot/external/2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae.txt": "foo",
                ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
                "tests/test_something.py": """\
from inline_snapshot import outsource, snapshot

from inline_snapshot import external


def test_something():
    outsource("blub")

    assert outsource("foo") == snapshot(external("hash:2c26b46b68ff*.txt"))

    \
""",
            }
        ),
        returncode=1,
        outcomes={"passed": 1, "errors": 1},
    ).run_pytest(
        [], changed_files=snapshot({})
    )


def test_persist_twice():
    Example("""\
from inline_snapshot import snapshot,outsource

def test_a():
    assert outsource("testabc") == snapshot()
    assert 1+1==snapshot()
""").run_pytest(
        ["--inline-snapshot=create"],
        returncode=1,
        changed_files={
            ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
            "tests/__inline_snapshot__/test_something/test_a/f728b4fa-4248-4e3a-8a5d-2f346baa9455.txt": "testabc",
            "tests/test_something.py": """\
from inline_snapshot import snapshot,outsource

from inline_snapshot import external

def test_a():
    assert outsource("testabc") == snapshot(external("uuid:f728b4fa-4248-4e3a-8a5d-2f346baa9455.txt"))
    assert 1+1==snapshot(2)
""",
        },
        outcomes={"passed": 1, "errors": 1},
    ).change_code(lambda text: text.replace("snapshot(2)", "snapshot()")).run_pytest(
        ["--inline-snapshot=create"],
        returncode=1,
        changed_files={"tests/test_something.py": """\
from inline_snapshot import snapshot,outsource

from inline_snapshot import external

def test_a():
    assert outsource("testabc") == snapshot(external("uuid:f728b4fa-4248-4e3a-8a5d-2f346baa9455.txt"))
    assert 1+1==snapshot(2)
"""},
        outcomes={"passed": 1, "errors": 1},
    )


def test_disable():
    Example("""
from inline_snapshot import external, snapshot,outsource

def test_something():
    assert outsource("foo") == snapshot()
    assert "foo" == external()
""").run_pytest(
        ["--inline-snapshot=create"],
        changed_files=snapshot(
            {
                ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
                "tests/__inline_snapshot__/test_something/test_something/eb1167b3-67a9-4378-bc65-c1e582e2e662.txt": "foo",
                "tests/__inline_snapshot__/test_something/test_something/f728b4fa-4248-4e3a-8a5d-2f346baa9455.txt": "foo",
                "tests/test_something.py": """\

from inline_snapshot import external, snapshot,outsource

def test_something():
    assert outsource("foo") == snapshot(external("uuid:eb1167b3-67a9-4378-bc65-c1e582e2e662.txt"))
    assert "foo" == external("uuid:f728b4fa-4248-4e3a-8a5d-2f346baa9455.txt")
""",
            }
        ),
        returncode=1,
        outcomes={"passed": 1, "errors": 1},
    ).run_pytest(["--inline-snapshot=disable"])

    Example("""
from inline_snapshot import external

def test_something():
    assert "foo" == external("hash:aaaaaaaaaaaa*.txt")
""").run_pytest(
        ["--inline-snapshot=disable"],
        error=snapshot("""\
>       assert "foo" == external("hash:aaaaaaaaaaaa*.txt")
>           raise StorageLookupError(
E           inline_snapshot._external._storage._protocol.StorageLookupError: hash 'aaaaaaaaaaaa*.txt' is not found in the HashStorage
"""),
        returncode=1,
        outcomes={"failed": 1},
    )


def test_show_diff():
    Example("""
from inline_snapshot import external

def test_a():
    n=3
    assert "\\n".join(map(str,range(n))) == external()
    """).run_pytest(
        ["--inline-snapshot=create"],
        report=snapshot("""\
------------------------------- Create snapshots -------------------------------
+-------------------------- tests/test_something.py ---------------------------+
| @@ -3,5 +3,5 @@                                                              |
|                                                                              |
|                                                                              |
|  def test_a():                                                               |
|      n=3                                                                     |
| -    assert "\\n".join(map(str,range(n))) == external()                       |
| +    assert "\\n".join(map(str,range(n))) ==                                  |
| external("uuid:e3e70682-c209-4cac-a29f-6fbed82c07cd.txt")                    |
+------------------------------------------------------------------------------+
+--------------- uuid:e3e70682-c209-4cac-a29f-6fbed82c07cd.txt ----------------+
| 0                                                                            |
| 1                                                                            |
| 2                                                                            |
+------------------------------------------------------------------------------+
These changes will be applied, because you used create\
"""),
        returncode=1,
        changed_files={
            ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
            "tests/__inline_snapshot__/test_something/test_a/e3e70682-c209-4cac-a29f-6fbed82c07cd.txt": """\
0
1
2\
""",
            "tests/test_something.py": """\

from inline_snapshot import external

def test_a():
    n=3
    assert "\\n".join(map(str,range(n))) == external("uuid:e3e70682-c209-4cac-a29f-6fbed82c07cd.txt")
    \
""",
        },
        outcomes={"passed": 1, "errors": 1},
    ).change_code(lambda text: text.replace("n=3", "n=5")).run_pytest(
        ["--inline-snapshot=fix"],
        report=snapshot("""\
+--------------- uuid:e3e70682-c209-4cac-a29f-6fbed82c07cd.txt ----------------+
| @@ -1,3 +1,5 @@                                                              |
|                                                                              |
|  0                                                                           |
|  1                                                                           |
|  2                                                                           |
| +3                                                                           |
| +4                                                                           |
+------------------------------------------------------------------------------+
These changes will be applied, because you used fix\
"""),
        returncode=1,
        changed_files={
            "tests/__inline_snapshot__/test_something/test_a/e3e70682-c209-4cac-a29f-6fbed82c07cd.txt": """\
0
1
2
3
4\
"""
        },
        outcomes={"passed": 1, "errors": 1},
    )


def test_double_eq():
    Example("""
from inline_snapshot import external

def test_a():
    assert "hi" == external(".json") == external(".txt")
    """).run_pytest(
        ["--inline-snapshot=create"],
        error=snapshot("""\
>       assert "hi" == external(".json") == external(".txt")
E       inline_snapshot._exceptions.UsageError: you cannot compare external(...) with external(...)
"""),
        returncode=1,
        changed_files={
            ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
            "tests/__inline_snapshot__/test_something/test_a/e3e70682-c209-4cac-a29f-6fbed82c07cd.json": '"hi"',
            "tests/test_something.py": """\

from inline_snapshot import external

def test_a():
    assert "hi" == external("uuid:e3e70682-c209-4cac-a29f-6fbed82c07cd.json") == external(".txt")
    \
""",
        },
        outcomes={"failed": 1, "errors": 1},
    )


def test_external_eq_snapshot():
    Example("""
from inline_snapshot import external, snapshot

def test_a():
    assert "hi" == external(".json") == snapshot(".txt")
    """).run_pytest(
        ["--inline-snapshot=create"],
        error=snapshot("""\
>       assert "hi" == external(".json") == snapshot(".txt")
E       inline_snapshot._exceptions.UsageError: you cannot compare external(...) with snapshot(...)
"""),
        returncode=1,
        changed_files={
            ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
            "tests/__inline_snapshot__/test_something/test_a/e3e70682-c209-4cac-a29f-6fbed82c07cd.json": '"hi"',
            "tests/test_something.py": """\

from inline_snapshot import external, snapshot

def test_a():
    assert "hi" == external("uuid:e3e70682-c209-4cac-a29f-6fbed82c07cd.json") == snapshot(".txt")
    \
""",
        },
        outcomes={"failed": 1, "errors": 1},
    )


def test_unknown_suffix():
    Example("""
from inline_snapshot import external

def test_a():
    assert "hi" == external("uuid:.blub")
    """).run_pytest(
        ["--inline-snapshot=create"],
        error=snapshot("""\
>       assert "hi" == external("uuid:.blub")
>           raise UsageError(
E           inline_snapshot._exceptions.UsageError: No format handler found for the given type 'str' and suffix '.blub'.
"""),
        returncode=1,
        outcomes={"failed": 1},
        changed_files={".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
"""},
    )


def test_unknown_type():
    Example("""
from inline_snapshot import external

class C:...

def test_a():
    assert C() == external("uuid:")
    """).run_pytest(
        ["--inline-snapshot=create"],
        error=snapshot("""\
>       assert C() == external("uuid:")
>           raise UsageError(
E           inline_snapshot._exceptions.UsageError: No format handler found for the given type 'C'.
"""),
        returncode=1,
        outcomes={"failed": 1},
        changed_files={".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
"""},
    )


def test_missing():

    Example("""
from inline_snapshot import external

def test_a():
    n=3
    assert "hi" == external()
    """).run_pytest(
        ["--inline-snapshot=short-report"],
        error=snapshot("""\
>       assert "hi" == external()
E       assert 'hi' == external("uuid:")
E        +  where external("uuid:") = external()
"""),
        report=snapshot("""\
Error: one snapshot is missing a value (--inline-snapshot=create)
You can also use --inline-snapshot=review to approve the changes interactively\
"""),
        returncode=1,
        outcomes={"failed": 1, "errors": 1},
    ).run_pytest(
        ["--inline-snapshot=disable"],
        error=snapshot("""\
>       assert "hi" == external()
>           raise UsageError(
E           inline_snapshot._exceptions.UsageError: cannot load external object from a non-existing location 'uuid:'
"""),
        report=snapshot(""),
        returncode=1,
        outcomes={"failed": 1},
    )


def test_report():
    # see https://github.com/15r10nk/inline-snapshot/issues/298

    Example("""\

from inline_snapshot import external


def test_example():
    n=5
    assert sorted([n, 2]) == external()


""").run_pytest(
        ["--inline-snapshot=report"],
        report=snapshot("""\
------------------------------- Create snapshots -------------------------------
+-------------------------- tests/test_something.py ---------------------------+
| @@ -4,6 +4,6 @@                                                              |
|                                                                              |
|                                                                              |
|  def test_example():                                                         |
|      n=5                                                                     |
| -    assert sorted([n, 2]) == external()                                     |
| +    assert sorted([n, 2]) ==                                                |
| external("uuid:e3e70682-c209-4cac-a29f-6fbed82c07cd.json")                   |
+------------------------------------------------------------------------------+
+--------------- uuid:e3e70682-c209-4cac-a29f-6fbed82c07cd.json ---------------+
| [                                                                            |
|   2,                                                                         |
|   5                                                                          |
| ]                                                                            |
+------------------------------------------------------------------------------+
These changes are not applied.
Use --inline-snapshot=create to apply them, or use the interactive mode with
--inline-snapshot=review\
"""),
        returncode=snapshot(1),
        error="""\
>       assert sorted([n, 2]) == external()
E       assert [2, 5] == external("uuid:")
E        +  where [2, 5] = sorted([5, 2])
E        +  and   external("uuid:") = external()
""",
        outcomes={"failed": 1, "errors": 1},
    ).run_inline(
        ["--inline-snapshot=create"],
        changed_files=snapshot(
            {
                ".inline-snapshot/files_using_external.txt": """\
# this file is generated by inline-snapshot and requires no manual edits (https://15r10nk.github.io/inline-snapshot/latest/external/external/#cleaning-up-old-externals)
tests/test_something.py
""",
                "tests/__inline_snapshot__/test_something/test_example/cd613e30-d8f1-4adf-91b7-584a2265b1f5.json": """\
[
  2,
  5
]\
""",
                "tests/test_something.py": """\

from inline_snapshot import external


def test_example():
    n=5
    assert sorted([n, 2]) == external("uuid:cd613e30-d8f1-4adf-91b7-584a2265b1f5.json")


""",
            }
        ),
    ).replace(
        "n=5", "n=8"
    ).run_pytest(
        ["--inline-snapshot=report"],
        report=snapshot("""\
+--------------- uuid:cd613e30-d8f1-4adf-91b7-584a2265b1f5.json ---------------+
| @@ -1,4 +1,4 @@                                                              |
|                                                                              |
|  [                                                                           |
|    2,                                                                        |
| -  5                                                                         |
| +  8                                                                         |
|  ]                                                                           |
+------------------------------------------------------------------------------+
These changes are not applied.
Use --inline-snapshot=fix to apply them, or use the interactive mode with
--inline-snapshot=review\
"""),
        returncode=snapshot(1),
        outcomes={"passed": 1, "errors": 1},
    )
