Skip to content

Commit 0841f4c

Browse files
[#306]: Document CLI tests
1 parent 239a167 commit 0841f4c

1 file changed

Lines changed: 45 additions & 0 deletions

File tree

‎tests/test_cli.py‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,24 +59,28 @@ def _cli_cache_file(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
5959

6060

6161
def test_get_local_file(person_file: Path):
62+
"""`pyld get` prints a local JSON-LD file as JSON."""
6263
result = runner.invoke(cli.pyld, ['get', str(person_file)])
6364
assert result.exit_code == 0, result.output
6465
assert json.loads(result.stdout) == PERSON
6566

6667

6768
def test_get_from_stdin():
69+
"""`pyld get -` reads JSON-LD from standard input and prints it."""
6870
result = runner.invoke(cli.pyld, ['get', '-'], input=json.dumps(PERSON))
6971
assert result.exit_code == 0, result.output
7072
assert json.loads(result.stdout) == PERSON
7173

7274

7375
def test_get_requires_input():
76+
"""`pyld get` without an input argument exits as a usage error."""
7477
result = runner.invoke(cli.pyld, ['get'])
7578
assert result.exit_code == 2
7679
assert 'Missing argument' in result.output
7780

7881

7982
def test_get_missing_file_exits_without_traceback(tmp_path: Path, capsys):
83+
"""A missing get input exits with a traceback hint and no stack trace."""
8084
missing = tmp_path / 'missing.jsonld'
8185
with pytest.raises(SystemExit) as exited:
8286
cli.main(['get', str(missing)])
@@ -103,6 +107,7 @@ def test_traceback_hint_repeats_the_failed_invocation(tmp_path: Path, capsys):
103107

104108

105109
def test_expand_local_file(person_file: Path):
110+
"""`pyld expand` expands a local JSON-LD file."""
106111
result = runner.invoke(cli.pyld, ['expand', str(person_file)])
107112
assert result.exit_code == 0, result.output
108113
assert json.loads(result.stdout) == [
@@ -111,6 +116,7 @@ def test_expand_local_file(person_file: Path):
111116

112117

113118
def test_expand_from_stdin():
119+
"""`pyld expand -` expands JSON-LD from standard input."""
114120
result = runner.invoke(cli.pyld, ['expand', '-'], input=json.dumps(PERSON))
115121
assert result.exit_code == 0, result.output
116122
assert json.loads(result.stdout) == [
@@ -119,6 +125,7 @@ def test_expand_from_stdin():
119125

120126

121127
def test_expand_with_base(tmp_path: Path):
128+
"""`--base` resolves relative IRIs during expansion."""
122129
input = {
123130
'@context': {
124131
'knows': {'@id': 'http://schema.org/knows', '@type': '@id'},
@@ -141,6 +148,7 @@ def test_expand_with_base(tmp_path: Path):
141148

142149

143150
def test_expand_with_context_from_stdin(tmp_path: Path):
151+
"""`--context -` expands using a context read from standard input."""
144152
input = {'name': 'Ada Lovelace'}
145153
input_path = write_json(tmp_path, 'person.jsonld', input)
146154
result = runner.invoke(
@@ -155,6 +163,7 @@ def test_expand_with_context_from_stdin(tmp_path: Path):
155163

156164

157165
def test_expand_with_context_file(tmp_path: Path):
166+
"""`--context` expands using a context loaded from a local file."""
158167
context_path = write_json(
159168
tmp_path,
160169
'context.jsonld',
@@ -172,6 +181,7 @@ def test_expand_with_context_file(tmp_path: Path):
172181

173182

174183
def test_invalid_json_on_stdin_exits_without_traceback(monkeypatch, capsys):
184+
"""Invalid JSON on stdin exits with a traceback hint and no stack trace."""
175185
monkeypatch.setattr(sys, 'stdin', io.StringIO('{not-json'))
176186
with pytest.raises(SystemExit) as exited:
177187
cli.main(['expand', '-'])
@@ -199,12 +209,14 @@ def test_bare_pyld_prints_help():
199209

200210

201211
def test_expand_requires_input():
212+
"""`pyld expand` without an input argument exits as a usage error."""
202213
result = runner.invoke(cli.pyld, ['expand'])
203214
assert result.exit_code == 2
204215
assert 'Missing argument' in result.output
205216

206217

207218
def test_cli_is_jsonld_11_only():
219+
"""The CLI does not expose `--processing-mode` and rejects `json-ld-1.0`."""
208220
help_result = runner.invoke(cli.pyld, ['expand', '--help'])
209221
assert help_result.exit_code == 0
210222
assert '--processing-mode' not in help_result.stdout
@@ -223,12 +235,14 @@ def test_cli_is_jsonld_11_only():
223235
['compact', 'flatten', 'frame', 'to-rdf', 'from-rdf'],
224236
)
225237
def test_new_commands_require_input(command: str):
238+
"""Transformation commands without an input argument exit as a usage error."""
226239
result = runner.invoke(cli.pyld, [command])
227240
assert result.exit_code == 2
228241
assert 'Missing argument' in result.output
229242

230243

231244
def test_compact_local_file_with_context_from_stdin(tmp_path: Path):
245+
"""`pyld compact` compacts a local file using a context from stdin."""
232246
input_path = write_json(tmp_path, 'person.jsonld', PERSON)
233247
result = runner.invoke(
234248
cli.pyld,
@@ -243,6 +257,7 @@ def test_compact_local_file_with_context_from_stdin(tmp_path: Path):
243257

244258

245259
def test_compact_from_stdin_with_context_file(tmp_path: Path):
260+
"""`pyld compact` compacts stdin using a context from a local file."""
246261
context_path = write_json(tmp_path, 'context.jsonld', {'@context': CONTEXT})
247262
result = runner.invoke(
248263
cli.pyld,
@@ -254,6 +269,7 @@ def test_compact_from_stdin_with_context_file(tmp_path: Path):
254269

255270

256271
def test_flatten_local_file(person_file: Path):
272+
"""`pyld flatten` flattens a local JSON-LD file."""
257273
result = runner.invoke(cli.pyld, ['flatten', str(person_file)])
258274
assert result.exit_code == 0, result.output
259275
assert json.loads(result.stdout)[0]['http://schema.org/name'] == [
@@ -262,6 +278,7 @@ def test_flatten_local_file(person_file: Path):
262278

263279

264280
def test_flatten_with_context_from_stdin(tmp_path: Path):
281+
"""`pyld flatten --context -` flattens using a context from stdin."""
265282
input_path = write_json(tmp_path, 'person.jsonld', PERSON)
266283
result = runner.invoke(
267284
cli.pyld,
@@ -273,6 +290,7 @@ def test_flatten_with_context_from_stdin(tmp_path: Path):
273290

274291

275292
def test_frame_local_file_with_frame_file(tmp_path: Path):
293+
"""`pyld frame` frames a local document with a local frame file."""
276294
input_path = write_json(tmp_path, 'person.jsonld', IDENTIFIED_PERSON)
277295
frame_path = write_json(tmp_path, 'frame.jsonld', FRAME)
278296
result = runner.invoke(
@@ -284,6 +302,7 @@ def test_frame_local_file_with_frame_file(tmp_path: Path):
284302

285303

286304
def test_frame_with_frame_from_stdin(tmp_path: Path):
305+
"""`pyld frame` frames a local document with a frame from stdin."""
287306
input_path = write_json(tmp_path, 'person.jsonld', IDENTIFIED_PERSON)
288307
result = runner.invoke(
289308
cli.pyld,
@@ -307,6 +326,7 @@ def test_frame_with_frame_from_stdin(tmp_path: Path):
307326
],
308327
)
309328
def test_multiple_operands_reject_stdin(command: str, secondary: str):
329+
"""Commands reject using standard input for more than one operand."""
310330
args = [command, '-']
311331
if command in ('compact', 'frame') and not secondary.startswith('--'):
312332
args.append(secondary)
@@ -320,6 +340,7 @@ def test_multiple_operands_reject_stdin(command: str, secondary: str):
320340

321341

322342
def test_to_rdf_local_file_writes_exact_nquads(tmp_path: Path):
343+
"""`pyld to-rdf` writes exact N-Quads for a local JSON-LD file."""
323344
input_path = write_json(tmp_path, 'person.jsonld', IDENTIFIED_PERSON)
324345
result = runner.invoke(cli.pyld, ['to-rdf', str(input_path)])
325346
assert result.exit_code == 0, result.output
@@ -328,6 +349,7 @@ def test_to_rdf_local_file_writes_exact_nquads(tmp_path: Path):
328349

329350

330351
def test_to_rdf_from_stdin_writes_exact_nquads():
352+
"""`pyld to-rdf -` writes exact N-Quads from standard input."""
331353
result = runner.invoke(
332354
cli.pyld,
333355
['to-rdf', '-'],
@@ -338,6 +360,7 @@ def test_to_rdf_from_stdin_writes_exact_nquads():
338360

339361

340362
def test_from_rdf_local_file(tmp_path: Path):
363+
"""`pyld from-rdf` converts a local N-Quads file to JSON-LD."""
341364
input_path = write_text(tmp_path, 'person.nq', NQUADS)
342365
result = runner.invoke(cli.pyld, ['from-rdf', str(input_path)])
343366
assert result.exit_code == 0, result.output
@@ -350,12 +373,14 @@ def test_from_rdf_local_file(tmp_path: Path):
350373

351374

352375
def test_from_rdf_from_stdin():
376+
"""`pyld from-rdf -` converts N-Quads from standard input to JSON-LD."""
353377
result = runner.invoke(cli.pyld, ['from-rdf', '-'], input=NQUADS)
354378
assert result.exit_code == 0, result.output
355379
assert json.loads(result.stdout)[0]['@id'] == 'http://example.com/ada'
356380

357381

358382
def test_from_rdf_rejects_remote_input():
383+
"""`pyld from-rdf` rejects remote URLs and requires a local path or `-`."""
359384
result = runner.invoke(
360385
cli.pyld,
361386
['from-rdf', 'https://example.com/person.nq'],
@@ -365,13 +390,15 @@ def test_from_rdf_rejects_remote_input():
365390

366391

367392
def test_from_rdf_help_describes_only_local_input():
393+
"""`from-rdf --help` describes local path or stdin input only."""
368394
result = runner.invoke(cli.pyld, ['from-rdf', '--help'])
369395
assert result.exit_code == 0, result.output
370396
assert 'Local path. Pass - to read from standard input.' in result.stdout
371397
assert 'Path or URL.' not in result.stdout
372398

373399

374400
def test_print_nquads_preserves_empty_output(monkeypatch: pytest.MonkeyPatch):
401+
"""Empty N-Quads output is printed without adding a trailing newline."""
375402
monkeypatch.setattr(jsonld, 'to_rdf', lambda *args, **kwargs: '')
376403
result = runner.invoke(cli.pyld, ['to-rdf', '-'], input=json.dumps(PERSON))
377404
assert result.exit_code == 0, result.output
@@ -500,6 +527,7 @@ def test_command_options_are_mapped_to_api_keys(
500527
function_name: str,
501528
expected: dict,
502529
):
530+
"""CLI flags are mapped to the corresponding JSON-LD API option keys."""
503531
captured = {}
504532

505533
def transform(*positional, options):
@@ -537,6 +565,7 @@ def test_omitted_cli_options_do_not_override_api_defaults(
537565
function_name: str,
538566
forced_keys: set[str],
539567
):
568+
"""Omitted CLI flags leave API defaults unset except forced keys."""
540569
captured = {}
541570

542571
def transform(*positional, options):
@@ -584,6 +613,7 @@ def test_jsonld_commands_preserve_remote_input_urls(
584613
args: list[str],
585614
function_name: str,
586615
):
616+
"""Remote input URLs are passed through to the JSON-LD API unchanged."""
587617
captured = {}
588618

589619
def transform(input_, *positional, options):
@@ -604,14 +634,17 @@ def transform(input_, *positional, options):
604634
],
605635
)
606636
def test_document_value_preserves_remote_urls(value: str):
637+
"""`document_value` leaves remote URLs unchanged."""
607638
assert cli_input.document_value(value) == value
608639

609640

610641
def test_document_value_treats_inline_json_as_a_path():
642+
"""`document_value` treats inline JSON text as a local path."""
611643
assert cli_input.document_value('{}') == Path('{}').resolve().as_uri()
612644

613645

614646
def test_missing_nquads_file_exits_without_traceback(tmp_path: Path, capsys):
647+
"""A missing from-rdf input exits with a traceback hint and no stack trace."""
615648
missing = tmp_path / 'missing.nq'
616649
with pytest.raises(SystemExit) as exited:
617650
cli.main(['from-rdf', str(missing)])
@@ -622,6 +655,7 @@ def test_missing_nquads_file_exits_without_traceback(tmp_path: Path, capsys):
622655

623656

624657
def test_invalid_nquads_exits_without_traceback(monkeypatch, capsys):
658+
"""Invalid N-Quads on stdin exits with a traceback hint and no stack trace."""
625659
monkeypatch.setattr(sys, 'stdin', io.StringIO('not n-quads'))
626660
with pytest.raises(SystemExit) as exited:
627661
cli.main(['from-rdf', '-'])
@@ -632,6 +666,7 @@ def test_invalid_nquads_exits_without_traceback(monkeypatch, capsys):
632666

633667

634668
def test_cache_clear(tmp_path: Path):
669+
"""`pyld cache clear` deletes the configured HTTP cache file."""
635670
cache_file = tmp_path / 'http_cache.sqlite'
636671
cache_file.write_text('cache', encoding='utf-8')
637672
result = runner.invoke(cli.pyld, ['cache', 'clear'])
@@ -641,6 +676,7 @@ def test_cache_clear(tmp_path: Path):
641676

642677

643678
def test_cache_clear_uses_env_var_cache_file(tmp_path: Path):
679+
"""`cache clear` deletes the cache file named by `PYLD_CACHE_FILE`."""
644680
cache_file = tmp_path / 'http_cache.sqlite'
645681
cache_file.write_text('cache', encoding='utf-8')
646682
result = runner.invoke(cli.pyld, ['cache', 'clear'])
@@ -652,6 +688,7 @@ def test_cache_file_option_overrides_env_var(
652688
tmp_path: Path,
653689
monkeypatch: pytest.MonkeyPatch,
654690
):
691+
"""`--cache-file` overrides `PYLD_CACHE_FILE` for cache clear."""
655692
env_cache = tmp_path / 'from-env.sqlite'
656693
option_cache = tmp_path / 'from-option.sqlite'
657694
env_cache.write_text('env', encoding='utf-8')
@@ -669,6 +706,7 @@ def test_cache_file_option_overrides_env_var(
669706
def test_parse_location_treats_windows_drive_as_path(
670707
monkeypatch: pytest.MonkeyPatch,
671708
):
709+
"""On Windows, drive-letter paths are treated as filesystem paths."""
672710
monkeypatch.setattr(cli_input.sys, 'platform', 'win32')
673711
for path in (
674712
r'C:\Users\ada\doc.jsonld',
@@ -682,29 +720,34 @@ def test_parse_location_treats_windows_drive_as_path(
682720
def test_parse_location_preserves_single_letter_scheme_outside_windows(
683721
monkeypatch: pytest.MonkeyPatch,
684722
):
723+
"""Outside Windows, a single-letter scheme is left as a URL."""
685724
monkeypatch.setattr(cli_input.sys, 'platform', 'linux')
686725
assert cli_input.parse_location('x:document') == 'x:document'
687726

688727

689728
def test_parse_location_preserves_http_urls():
729+
"""`parse_location` leaves HTTP(S) URLs unchanged."""
690730
assert cli_input.parse_location('https://example.com/x.jsonld') == (
691731
'https://example.com/x.jsonld'
692732
)
693733

694734

695735
def test_parse_location_resolves_local_path(tmp_path: Path):
736+
"""`parse_location` resolves a local path to an absolute Path."""
696737
path = write_json(tmp_path, 'person.jsonld', {})
697738
result = cli_input.parse_location(str(path))
698739
assert result == path.resolve()
699740
assert isinstance(result, Path)
700741

701742

702743
def test_document_url_converts_local_path_to_file_url(tmp_path: Path):
744+
"""`document_url` converts a local path to a file: URL."""
703745
path = write_json(tmp_path, 'person.jsonld', {})
704746
assert cli_input.document_url(str(path)) == path.as_uri()
705747

706748

707749
def test_document_url_preserves_http_url():
750+
"""`document_url` leaves HTTP(S) URLs unchanged."""
708751
assert cli_input.document_url('https://example.com/x.jsonld') == (
709752
'https://example.com/x.jsonld'
710753
)
@@ -714,6 +757,7 @@ def test_configured_cache_file_resolves_relative_path(
714757
tmp_path: Path,
715758
monkeypatch: pytest.MonkeyPatch,
716759
):
760+
"""`configured_cache_file` resolves a relative cache path against cwd."""
717761
monkeypatch.chdir(tmp_path)
718762
cli_state.current = State(cache_file=Path('rel.sqlite'))
719763
assert cli_input.configured_cache_file() == (tmp_path / 'rel.sqlite').resolve()
@@ -734,6 +778,7 @@ def test_cli_entry_exits_when_cli_deps_missing(
734778
monkeypatch: pytest.MonkeyPatch,
735779
capsys: pytest.CaptureFixture[str],
736780
):
781+
"""Missing CLI dependencies exit with an install hint for `PyLD[cli]`."""
737782
from pyld.cli import entry
738783

739784
def fail():

0 commit comments

Comments
 (0)