Coverage for tests/test_cli.py: 100%

43 statements  

« prev     ^ index     » next       coverage.py v7.17.2, created at 2026-11-09 14:41 +0000

1import io 

2import pathlib 

3import runpy 

4import sys 

5import types 

6import typing 

7 

8import pytest 

9 

10from archdocs import cli 

11from tests import diagram_rendering 

12 

13 

14_SERVICE_NAME: typing.Final = "cli-svc" 

15_CLI_ARGUMENTS: typing.Final = ( 

16 "render", 

17 "--root-dir", 

18 str(diagram_rendering.LITESTAR_ROOT), 

19 "--service-name", 

20 _SERVICE_NAME, 

21 "--kubernetes-dir", 

22 diagram_rendering.WITHOUT_MANIFESTS, 

23) 

24_USAGE_EXIT_CODE: typing.Final = 2 

25_FORMAT_OPTION: typing.Final = "--format" 

26_SERVICE_NODE: typing.Final = 'cli_svc{"cli-svc"}' 

27_SELF_HOSTED_MERMAID: typing.Final = "/static/mermaid.min.js?v=1&x=2" 

28_ALL_FORMAT_CASES: typing.Final = types.MappingProxyType( 

29 { 

30 "mermaid by default": ((), "graph TB\n", "\n", ("```", "<html")), 

31 "markdown": ((_FORMAT_OPTION, "markdown"), "```mermaid\ngraph TB\n", "\n```\n", ("<html",)), 

32 "html with self hosted mermaid": ( 

33 (_FORMAT_OPTION, "html", "--mermaid-script-url", _SELF_HOSTED_MERMAID), 

34 "<!DOCTYPE html>", 

35 "</html>", 

36 ("cdn.jsdelivr.net", _SELF_HOSTED_MERMAID), 

37 ), 

38 }, 

39) 

40 

41 

42@pytest.mark.parametrize( 

43 ("extra_arguments", "expected_start", "expected_end", "forbidden_parts"), 

44 _ALL_FORMAT_CASES.values(), 

45 ids=_ALL_FORMAT_CASES, 

46) 

47def test_every_format_is_written_to_a_file( 

48 tmp_path: pathlib.Path, 

49 extra_arguments: tuple[str, ...], 

50 expected_start: str, 

51 expected_end: str, 

52 forbidden_parts: tuple[str, ...], 

53) -> None: 

54 output_path: typing.Final = tmp_path / "architecture.out" 

55 

56 cli.run_command_line([*_CLI_ARGUMENTS, *extra_arguments, "--output", str(output_path)]) 

57 

58 rendered_output: typing.Final = output_path.read_text(encoding="utf-8") 

59 assert rendered_output.startswith(expected_start) 

60 assert rendered_output.endswith(expected_end) 

61 assert _SERVICE_NODE in rendered_output 

62 for one_forbidden_part in forbidden_parts: 

63 assert one_forbidden_part not in rendered_output, one_forbidden_part 

64 

65 

66def test_self_hosted_mermaid_is_escaped(tmp_path: pathlib.Path) -> None: 

67 output_path: typing.Final = tmp_path / "architecture.html" 

68 

69 cli.run_command_line( 

70 [ 

71 *_CLI_ARGUMENTS, 

72 _FORMAT_OPTION, 

73 "html", 

74 "--mermaid-script-url", 

75 _SELF_HOSTED_MERMAID, 

76 "--output", 

77 str(output_path), 

78 ], 

79 ) 

80 

81 assert '<script src="/static/mermaid.min.js?v=1&amp;x=2"></script>' in output_path.read_text(encoding="utf-8") 

82 

83 

84def test_module_run_prints_the_diagram(monkeypatch: pytest.MonkeyPatch) -> None: 

85 printed_output_buffer: typing.Final = io.StringIO() 

86 monkeypatch.setattr(sys, "argv", ["archdocs", *_CLI_ARGUMENTS]) 

87 monkeypatch.setattr(sys, "stdout", printed_output_buffer) 

88 

89 runpy.run_module("archdocs", run_name="__main__") 

90 

91 printed_output: typing.Final = printed_output_buffer.getvalue() 

92 assert printed_output.startswith("graph TB\n") 

93 assert _SERVICE_NODE in printed_output 

94 

95 

96@pytest.mark.parametrize( 

97 "every_argument", 

98 [(), ("render",), ("render", "--service-name", _SERVICE_NAME, _FORMAT_OPTION, "pdf")], 

99 ids=["no command", "no service name", "unknown format"], 

100) 

101def test_bad_arguments_exit_with_usage(every_argument: tuple[str, ...]) -> None: 

102 with pytest.raises(SystemExit) as exit_info: 

103 cli.run_command_line(list(every_argument)) 

104 

105 assert exit_info.value.code == _USAGE_EXIT_CODE