File size: 5,076 Bytes
2857cf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
from __future__ import annotations

from io import StringIO
from pathlib import Path

from PIL import Image
import pytest
from rich.console import Console
from typer.testing import CliRunner

import kneiff.cli.image as cli_image
import kneiff.utils.image.caption.server as caption_server
import kneiff.utils.image.tag_jtp3 as tag_jtp3
from kneiff.progress import ProgressUpdate
from kneiff.utils.image.caption.batch import (
    CaptionBatchItemResult,
    CaptionBatchResult,
)
from tests._cli_helpers import invoke_cli


pytestmark = pytest.mark.usefixtures("isolated_cli_project")


def _reject_progress(*args: object, **kwargs: object) -> None:
    del args, kwargs
    raise AssertionError("This command must not create a progress reporter.")


def test_concat_and_rename_do_not_create_progress(
    monkeypatch: pytest.MonkeyPatch,
    tmp_path: Path,
) -> None:
    first = tmp_path / "first.png"
    second = tmp_path / "second.png"
    Image.new("RGB", (2, 2), color="red").save(first)
    Image.new("RGB", (2, 2), color="blue").save(second)
    monkeypatch.setattr(cli_image, "CliProgress", _reject_progress)

    concat_result = invoke_cli(
        CliRunner(),
        ["img", "concat", str(first), str(second), "-o", str(tmp_path / "out.png")],
    )
    rename_result = invoke_cli(
        CliRunner(),
        ["img", "rename", str(first), "--base-name", "sample"],
    )

    assert concat_result.exit_code == 0, concat_result.output
    assert rename_result.exit_code == 0, rename_result.output


def test_tag_does_not_create_progress(
    monkeypatch: pytest.MonkeyPatch,
    tmp_path: Path,
) -> None:
    source = tmp_path / "source.png"
    source.write_bytes(b"image")
    monkeypatch.setattr(cli_image, "CliProgress", _reject_progress)
    monkeypatch.setattr(tag_jtp3, "run_jtp3", lambda *args, **kwargs: None)

    result = invoke_cli(CliRunner(), ["img", "tag", str(source)])

    assert result.exit_code == 0, result.output


def test_single_image_caption_does_not_create_progress(
    monkeypatch: pytest.MonkeyPatch,
    tmp_path: Path,
) -> None:
    source = tmp_path / "source.png"
    source.write_bytes(b"image")
    monkeypatch.setattr(cli_image, "CliProgress", _reject_progress)
    monkeypatch.setattr(
        caption_server,
        "caption_image_with_server",
        lambda **kwargs: "one caption",
    )

    result = invoke_cli(CliRunner(), ["img", "caption", str(source)])

    assert result.exit_code == 0, result.output
    assert result.output.strip() == "one caption"


def test_directory_caption_redirected_output_keeps_instruction_and_dry_run(
    monkeypatch: pytest.MonkeyPatch,
    tmp_path: Path,
) -> None:
    source = tmp_path / "source.png"
    source.write_bytes(b"image")

    def fake_run(jobs, **kwargs: object) -> CaptionBatchResult:
        job = jobs[0]
        instruction_callback = kwargs["instruction_callback"]
        item_callback = kwargs["item_callback"]
        progress_callback = kwargs["progress_callback"]
        assert callable(instruction_callback)
        assert callable(item_callback)
        assert callable(progress_callback)
        instruction_callback("Instruction:\nDescribe the image.\n")
        item = CaptionBatchItemResult(
            job=job,
            status="planned",
            caption="one dry-run caption",
        )
        item_callback(item)
        progress_callback(ProgressUpdate("Caption 1/1 · planned", advance=1))
        return CaptionBatchResult(items=(item,))

    monkeypatch.setattr(caption_server, "run_caption_batch_with_server", fake_run)

    result = invoke_cli(
        CliRunner(),
        ["img", "caption", str(tmp_path), "--dry-run"],
    )

    assert result.exit_code == 0, result.output
    assert "Instruction:\nDescribe the image." in result.output
    assert "source.png -> one dry-run caption" in result.output
    assert "\x1b[" not in result.output


def test_directory_caption_terminal_hides_instruction_dump(
    monkeypatch: pytest.MonkeyPatch,
    tmp_path: Path,
) -> None:
    source = tmp_path / "source.png"
    source.write_bytes(b"image")
    terminal_output = StringIO()
    console = Console(
        file=terminal_output,
        force_terminal=True,
        color_system=None,
        width=100,
    )
    monkeypatch.setattr(cli_image, "stderr_progress_console", lambda: console)

    def fake_run(jobs, **kwargs: object) -> CaptionBatchResult:
        assert kwargs["instruction_callback"] is None
        progress_callback = kwargs["progress_callback"]
        assert callable(progress_callback)
        item = CaptionBatchItemResult(job=jobs[0], status="written", caption="caption")
        progress_callback(ProgressUpdate("Caption 1/1", advance=1))
        return CaptionBatchResult(items=(item,))

    monkeypatch.setattr(caption_server, "run_caption_batch_with_server", fake_run)

    result = invoke_cli(CliRunner(), ["img", "caption", str(tmp_path)])

    assert result.exit_code == 0, result.output
    assert "Instruction:" not in result.output
    assert "Captioning complete" in terminal_output.getvalue()