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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
|
import os
import textwrap
import pytest
from iniconfig import IniConfig
import lektor_ng.quickstart
from lektor_ng.cli.cli_old import cli
from lektor_ng.inifile import IniFile
@pytest.fixture(scope="session")
def can_symlink(tmp_path_factory):
"""Test whether current user has sufficient privileges to create symlinks."""
if os.name == "nt":
tmp_path = tmp_path_factory.mktemp("symlink-test")
try:
os.symlink("foo", tmp_path / "test")
except OSError as exc:
# Error Code 1314 - A required privilege is not held by the client
# pylint: disable=no-member
if exc.winerror != 1314:
raise
return False
return True
@pytest.fixture
def default_author(mocker):
author = "J. Random Hacker"
mocker.patch.object(lektor_ng.quickstart, "get_default_author", spec=True, return_value=author)
return author
@pytest.fixture
def default_author_email(mocker):
email = "jrh@example.org"
mocker.patch.object(lektor_ng.quickstart, "get_default_author_email", spec=True, return_value=email)
return email
def _pack_lines(*lines: str) -> str:
"""Pack input lines into single string."""
return "\n".join(lines) + "\n"
# new-plugin
def test_new_plugin(project_cli_runner):
result = project_cli_runner.invoke(
cli,
["dev", "new-plugin"],
input=_pack_lines("Plugin Name", "", "Author Name", "author@email.com", "y"),
)
assert "Create Plugin?" in result.output
assert result.exit_code == 0
path = os.path.join("packages", "plugin-name")
assert set(os.listdir(path)) == {
"lektor_plugin_name.py",
"pyproject.toml",
"setup.cfg",
".gitignore",
"README.md",
}
# gitignore
gitignore_expected = textwrap.dedent(
"""
/dist
/build
__pycache__
*.egg-info
"""
).strip()
with open(os.path.join(path, ".gitignore"), encoding="utf-8") as f:
gitignore_contents = f.read().strip()
assert gitignore_contents == gitignore_expected
# README.md
readme_expected = textwrap.dedent(
"""
# Plugin Name
This is where a description of your plugin goes.
Provide usage instructions here.
"""
).strip()
with open(os.path.join(path, "README.md"), encoding="utf-8") as f:
readme_contents = f.read().strip()
assert readme_contents == readme_expected
setup = IniConfig(os.path.join(path, "setup.cfg"))
assert setup.get("metadata", "name") == "lektor-plugin-name"
assert setup.get("metadata", "author") == "Author Name"
assert setup.get("metadata", "author_email") == "author@email.com"
assert setup.get("options", "py_modules") == "lektor_plugin_name"
assert setup.get("options.entry_points", "lektor.plugins") == "plugin-name = lektor_plugin_name:PluginNamePlugin"
# plugin.py
plugin_expected = textwrap.dedent(
"""
from lektor_ng.pluginsystem import Plugin
class PluginNamePlugin(Plugin):
name = 'Plugin Name'
description = "Add your description here."
def on_process_template_context(self, context, **extra):
def test_function():
return f"Value from plugin {self.name}"
context["test_function"] = test_function
"""
).strip()
with open(os.path.join(path, "lektor_plugin_name.py"), encoding="utf-8") as f:
plugin_contents = f.read().strip()
assert plugin_contents == plugin_expected
def test_new_plugin_abort_plugin_exists(project_cli_runner):
path = "packages"
os.mkdir(path)
os.mkdir(os.path.join(path, "plugin-name"))
input = "Plugin Name\n\nAuthor Name\nauthor@email.com\ny\n"
result = project_cli_runner.invoke(cli, ["dev", "new-plugin"], input=input)
assert "Aborted!" in result.output
assert result.exit_code == 1
def test_new_plugin_abort_cancel(project_cli_runner):
result = project_cli_runner.invoke(
cli,
["dev", "new-plugin"],
input=_pack_lines("Plugin Name", "", "Author Name", "author@email.com", "n"),
)
assert "Aborted!" in result.output
assert result.exit_code == 1
def test_new_plugin_name_only(project_cli_runner, default_author, default_author_email):
result = project_cli_runner.invoke(
cli,
["dev", "new-plugin"],
input=_pack_lines("Plugin Name", "", "", "", "y"),
)
assert "Create Plugin?" in result.output
assert result.exit_code == 0
path = "packages"
assert os.listdir(path) == ["plugin-name"]
setup = IniConfig(os.path.join(path, "plugin-name", "setup.cfg"))
assert setup.get("metadata", "author") == default_author
assert setup.get("metadata", "author_email") == default_author_email
def test_new_plugin_name_param(project_cli_runner):
result = project_cli_runner.invoke(
cli,
["dev", "new-plugin", "plugin-name"],
input=_pack_lines("", "Author Name", "author@email.com", "y"),
)
assert "Create Plugin?" in result.output
assert result.exit_code == 0
path = "packages"
assert os.listdir(path) == ["plugin-name"]
def test_new_plugin_path(project_cli_runner):
result = project_cli_runner.invoke(
cli,
["dev", "new-plugin"],
input=_pack_lines("Plugin Name", "path", "Author Name", "author@email.com", "y"),
)
assert "Create Plugin?" in result.output
assert result.exit_code == 0
path = "path"
assert set(os.listdir(path)) == {
"lektor_plugin_name.py",
"pyproject.toml",
"setup.cfg",
".gitignore",
"README.md",
}
def test_new_plugin_path_param(project_cli_runner):
result = project_cli_runner.invoke(
cli,
["dev", "new-plugin", "--path", "path"],
input=_pack_lines("Plugin Name", "Author Name", "author@email.com", "y"),
)
assert "Create Plugin?" in result.output
assert result.exit_code == 0
path = "path"
assert set(os.listdir(path)) == {
"lektor_plugin_name.py",
"pyproject.toml",
"setup.cfg",
".gitignore",
"README.md",
}
def test_new_plugin_path_and_name_params(project_cli_runner):
result = project_cli_runner.invoke(
cli,
["dev", "new-plugin", "plugin-name", "--path", "path"],
input=_pack_lines("Author Name", "author@email.com", "y"),
)
assert "Create Plugin?" in result.output
assert result.exit_code == 0
path = "path"
assert set(os.listdir(path)) == {
"lektor_plugin_name.py",
"pyproject.toml",
"setup.cfg",
".gitignore",
"README.md",
}
# new-theme
def test_new_theme(project_cli_runner, can_symlink):
result = project_cli_runner.invoke(
cli,
["dev", "new-theme"],
input=_pack_lines("Lektor Theme Name", "", "Author Name", "author@email.com", "y"),
)
assert "Create Theme?" in result.output
assert result.exit_code == 0
path = os.path.join("themes", "lektor-theme-name")
assert set(os.listdir(path)) == {"example-site", "images", "README.md", "theme.ini"}
assert set(os.listdir(os.path.join(path, "images"))) == {"homepage.png"}
assert set(os.listdir(os.path.join(path, "example-site"))) == {
"lektor-theme-name.lektorproject",
"README.md",
"themes",
}
if can_symlink:
assert os.readlink(os.path.join(path, "example-site/themes/lektor-theme-name")) == "../../../lektor-theme-name"
theme_inifile = IniFile(os.path.join(path, "theme.ini"))
assert theme_inifile["theme.name"] == "Lektor Theme Name"
assert theme_inifile["author.email"] == "author@email.com"
assert theme_inifile["author.name"] == "Author Name"
with open(os.path.join(path, "README.md"), encoding="utf-8") as f:
readme_contents = f.read().strip()
assert "Lektor Theme Name" in readme_contents
def test_new_theme_abort_theme_exists(project_cli_runner):
path = "themes"
os.mkdir(path)
os.mkdir(os.path.join(path, "lektor-theme-name"))
input = "Lektor Name\n\nAuthor Name\nauthor@email.com\ny\n"
result = project_cli_runner.invoke(cli, ["dev", "new-theme"], input=input)
assert "Aborted!" in result.output
assert result.exit_code == 1
def test_new_theme_abort_cancel(project_cli_runner):
result = project_cli_runner.invoke(
cli,
["dev", "new-theme"],
input=_pack_lines("Theme Name", "", "Author Name", "author@email.com", "n"),
)
assert "Aborted!" in result.output
assert result.exit_code == 1
def test_new_theme_name_only(project_cli_runner, can_symlink, default_author, default_author_email):
result = project_cli_runner.invoke(
cli,
["dev", "new-theme"],
input=_pack_lines("Lektor Name Theme", "", "", "", "y"),
)
assert "Create Theme?" in result.output
assert result.exit_code == 0
path = os.path.join("themes", "lektor-theme-name")
assert set(os.listdir(path)) == {"example-site", "images", "README.md", "theme.ini"}
assert set(os.listdir(os.path.join(path, "images"))) == {"homepage.png"}
assert set(os.listdir(os.path.join(path, "example-site"))) == {
"lektor-theme-name.lektorproject",
"README.md",
"themes",
}
if can_symlink:
assert os.readlink(os.path.join(path, "example-site/themes/lektor-theme-name")) == "../../../lektor-theme-name"
theme_inifile = IniFile(os.path.join(path, "theme.ini"))
assert theme_inifile["theme.name"] == "Lektor Name Theme"
assert theme_inifile["author.email"] == default_author_email
assert theme_inifile["author.name"] == default_author
with open(os.path.join(path, "README.md"), encoding="utf-8") as f:
readme_contents = f.read().strip()
assert "Lektor Name Theme" in readme_contents
def test_new_theme_name_param(project_cli_runner):
result = project_cli_runner.invoke(
cli,
["dev", "new-theme", "theme-name"],
input=_pack_lines("", "Author Name", "author@email.com", "y"),
)
assert "Create Theme?" in result.output
assert result.exit_code == 0
path = "themes"
assert os.listdir(path) == ["lektor-theme-name"]
def test_new_theme_path(project_cli_runner):
result = project_cli_runner.invoke(
cli,
["dev", "new-theme"],
input=_pack_lines("Theme Name", "path", "Author Name", "author@email.com", "y"),
)
assert "Create Theme?" in result.output
assert result.exit_code == 0
path = "path"
assert set(os.listdir(path)) == {"example-site", "images", "theme.ini", "README.md"}
def test_new_theme_path_param(project_cli_runner):
result = project_cli_runner.invoke(
cli,
["dev", "new-theme", "--path", "path"],
input=_pack_lines("Theme Name", "Author Name", "author@email.com", "y"),
)
assert "Create Theme?" in result.output
assert result.exit_code == 0
path = "path"
assert set(os.listdir(path)) == {"example-site", "images", "theme.ini", "README.md"}
def test_new_theme_path_and_name_params(project_cli_runner):
result = project_cli_runner.invoke(
cli,
["dev", "new-theme", "theme-name", "--path", "path"],
input=_pack_lines("Author Name", "author@email.com", "y"),
)
assert "Create Theme?" in result.output
assert result.exit_code == 0
path = "path"
assert set(os.listdir(path)) == {"example-site", "images", "theme.ini", "README.md"}
@pytest.mark.parametrize(
("theme_name", "expected_id"),
(
("Lektor New Theme", "lektor-theme-new"),
("Lektor Theme", "lektor-theme-theme"),
("New Theme", "lektor-theme-new"),
("New", "lektor-theme-new"),
("Theme", "lektor-theme-theme"),
("Lektor", "lektor-theme-lektor"),
("Lektor Theme New", "lektor-theme-new"),
),
)
@pytest.mark.usefixtures("default_author", "default_author_email")
def test_new_theme_varying_names(project_cli_runner, theme_name, expected_id):
result = project_cli_runner.invoke(
cli,
["dev", "new-theme"],
input=_pack_lines(f"{theme_name}", "", "", "", "y"),
)
assert "Create Theme?" in result.output
assert result.exit_code == 0
assert expected_id in os.listdir("themes")
path = os.path.join("themes", expected_id, "example-site")
assert expected_id + ".lektorproject" in os.listdir(path)
|