File: test_edit.py

package info (click to toggle)
python-cyclopts 3.12.0-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 3,288 kB
  • sloc: python: 11,445; makefile: 24
file content (174 lines) | stat: -rw-r--r-- 5,404 bytes parent folder | download | duplicates (2)
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import subprocess
from pathlib import Path

import pytest

from cyclopts._edit import (
    EditorDidNotChangeError,
    EditorDidNotSaveError,
    EditorError,
    EditorNotFoundError,
    edit,
)


@pytest.fixture
def mock_editor():
    """Mock editor that simulates saving file with edited content."""

    def fake_editor(args):
        Path(args[1]).write_text("edited content")
        return 0

    return fake_editor


def test_basic_edit(mocker, mock_editor, monkeypatch):
    """Test basic editing functionality."""
    monkeypatch.setenv("EDITOR", "test_editor")
    mocker.patch("shutil.which", return_value=True)
    mocker.patch("subprocess.check_call", side_effect=mock_editor)

    result = edit("initial text")
    assert result == "edited content"


def test_custom_path(mocker, mock_editor, tmp_path, monkeypatch):
    """Test editing with custom path."""
    custom_path = tmp_path / "custom.txt"
    monkeypatch.setenv("EDITOR", "test_editor")
    mocker.patch("shutil.which", return_value=True)
    mocker.patch("subprocess.check_call", side_effect=mock_editor)

    result = edit("initial text", path=custom_path)
    assert result == "edited content"


def test_editor_not_found(mocker, monkeypatch):
    """Test behavior when no editor is found."""
    monkeypatch.delenv("EDITOR", raising=False)
    mocker.patch("shutil.which", return_value=False)

    with pytest.raises(EditorNotFoundError):
        edit("test")


def test_did_not_save(mocker, monkeypatch):
    """Test behavior when user doesn't save."""
    monkeypatch.setenv("EDITOR", "test_editor")

    def fake_editor(_):  # Doesn't "save"
        return 0

    mocker.patch("shutil.which", return_value=True)
    mocker.patch("subprocess.check_call", side_effect=fake_editor)

    with pytest.raises(EditorDidNotSaveError):
        edit("initial text", save=True)


def test_did_not_change(mocker, monkeypatch):
    """Test behavior when content isn't changed."""
    monkeypatch.setenv("EDITOR", "test_editor")
    initial_text = "unchanged text"

    def fake_editor(args):
        assert args[0] == "test_editor"
        Path(args[1]).write_text(initial_text)
        return 0

    mocker.patch("shutil.which", return_value=True)
    mocker.patch("subprocess.check_call", side_effect=fake_editor)

    with pytest.raises(EditorDidNotChangeError):
        edit(initial_text, required=True)


def test_editor_error(mocker, monkeypatch):
    """Test handling of editor errors."""
    monkeypatch.setenv("EDITOR", "test_editor")
    mocker.patch("shutil.which", return_value=True)
    mocker.patch("subprocess.check_call", side_effect=subprocess.CalledProcessError(1, "test_editor"))

    with pytest.raises(EditorError) as exc_info:
        edit("test")
    assert "status 1" in str(exc_info.value)


def test_custom_encoding(mocker, tmp_path, monkeypatch):
    """Test custom encoding support."""
    test_path = tmp_path / "test.txt"
    monkeypatch.setenv("EDITOR", "test_editor")

    def fake_editor_with_encoding(args):
        assert args[0] == "test_editor"
        Path(args[1]).write_text("текст", encoding="utf-16")
        return 0

    mocker.patch("shutil.which", return_value=True)
    mocker.patch("subprocess.check_call", side_effect=fake_editor_with_encoding)

    result = edit("initial", path=test_path, encoding="utf-16")
    assert result == "текст"


def test_fallback_editors(mocker, mock_editor, monkeypatch):
    """Test fallback editor selection."""
    monkeypatch.delenv("EDITOR", raising=False)

    def mock_which(editor_name):
        return editor_name == "vim"

    mocker.patch("shutil.which", side_effect=mock_which)
    mock_check_call = mocker.patch("subprocess.check_call", side_effect=mock_editor)

    result = edit("test", fallback_editors=["emacs", "vim", "nano"])
    assert result == "edited content"
    assert mock_check_call.call_args_list[0].args[0][0] == "vim"


def test_editor_args(mocker, monkeypatch):
    """Test passing additional arguments to editor."""
    monkeypatch.setenv("EDITOR", "test_editor")

    def check_editor_args(args):
        assert args[0] == "test_editor"
        assert "--no-splash" in args
        Path(args[1]).write_text("edited with args")
        return 0

    mocker.patch("shutil.which", return_value=True)
    mocker.patch("subprocess.check_call", side_effect=check_editor_args)

    result = edit("test", editor_args=["--no-splash"])
    assert result == "edited with args"


def test_optional_change(mocker, monkeypatch):
    """Test when content changes are optional."""
    monkeypatch.setenv("EDITOR", "test_editor")
    initial_text = "unchanged"

    def fake_editor(args):
        assert args[0] == "test_editor"
        Path(args[1]).write_text(initial_text)
        return 0

    mocker.patch("shutil.which", return_value=True)
    mocker.patch("subprocess.check_call", side_effect=fake_editor)

    # Should not raise DidNotChangeError
    result = edit(initial_text, required=False)
    assert result == initial_text


def test_file_cleanup(mocker, tmp_path, monkeypatch, mock_editor):
    """Test temporary file cleanup."""
    test_path = tmp_path / "cleanup_test.txt"
    monkeypatch.setenv("EDITOR", "test_editor")

    mocker.patch("shutil.which", return_value=True)
    mocker.patch("subprocess.check_call", side_effect=mock_editor)

    edit("test", path=test_path)
    assert not test_path.exists()