diff options
Diffstat (limited to '')
-rw-r--r-- | tests/lint_tests/conftest.py | 41 | ||||
-rw-r--r-- | tests/lint_tests/lint_tutil.py | 60 | ||||
-rw-r--r-- | tests/lint_tests/test_lint_changelog.py | 90 | ||||
-rw-r--r-- | tests/lint_tests/test_lint_dctrl.py | 143 | ||||
-rw-r--r-- | tests/lint_tests/test_lint_debputy.py | 207 | ||||
-rw-r--r-- | tests/lsp_tests/conftest.py | 36 | ||||
-rw-r--r-- | tests/lsp_tests/lsp_tutil.py | 5 | ||||
-rw-r--r-- | tests/lsp_tests/test_lsp_dctrl.py | 88 | ||||
-rw-r--r-- | tests/lsp_tests/test_lsp_debputy_manifest_completer.py | 21 |
9 files changed, 610 insertions, 81 deletions
diff --git a/tests/lint_tests/conftest.py b/tests/lint_tests/conftest.py index d08f5ca..2c54eb7 100644 --- a/tests/lint_tests/conftest.py +++ b/tests/lint_tests/conftest.py @@ -1,16 +1,22 @@ import pytest +from debian.debian_support import DpkgArchTable -from debputy.lsp.lsp_features import lsp_set_plugin_features -from debputy.plugin.api.feature_set import PluginProvidedFeatureSet +from debputy._deb_options_profiles import DebBuildOptionsAndProfiles +from debputy.architecture_support import DpkgArchitectureBuildProcessValuesTable +from debputy.packages import DctrlParser from debputy.util import setup_logging try: from lsprotocol.types import Diagnostic + from debputy.lsp.spellchecking import disable_spellchecking HAS_LSPROTOCOL = True except ImportError: HAS_LSPROTOCOL = False + def disable_spellchecking() -> None: + pass + @pytest.fixture(scope="session", autouse=True) def enable_logging() -> None: @@ -19,12 +25,25 @@ def enable_logging() -> None: setup_logging(reconfigure_logging=True) -@pytest.fixture(autouse=True) -def setup_feature_set( - debputy_plugin_feature_set: PluginProvidedFeatureSet, -) -> None: - lsp_set_plugin_features(debputy_plugin_feature_set) - try: - yield - finally: - lsp_set_plugin_features(None) +@pytest.fixture(scope="session", autouse=True) +def disable_spellchecking_fixture() -> None: + # CI/The buildd does not install relevant, so this is mostly about ensuring + # consistent behavior between clean and "unclean" build/test environments + disable_spellchecking() + + +@pytest.fixture +def lint_dctrl_parser( + dpkg_arch_query: DpkgArchTable, + amd64_dpkg_architecture_variables: DpkgArchitectureBuildProcessValuesTable, + no_profiles_or_build_options: DebBuildOptionsAndProfiles, +) -> DctrlParser: + return DctrlParser( + frozenset(), + frozenset(), + True, + True, + amd64_dpkg_architecture_variables, + dpkg_arch_query, + no_profiles_or_build_options, + ) diff --git a/tests/lint_tests/lint_tutil.py b/tests/lint_tests/lint_tutil.py index d4f654c..83b69fd 100644 --- a/tests/lint_tests/lint_tutil.py +++ b/tests/lint_tests/lint_tutil.py @@ -1,9 +1,16 @@ import collections -from typing import List, Optional, Mapping, Any +from typing import List, Optional, Mapping, Any, Callable import pytest -from debputy.linting.lint_util import LinterImpl, LinterPositionCodec +from debputy.linting.lint_util import ( + LinterImpl, + LinterPositionCodec, + LintStateImpl, + LintState, +) +from debputy.packages import DctrlParser +from debputy.plugin.api.feature_set import PluginProvidedFeatureSet try: from lsprotocol.types import Diagnostic, DiagnosticSeverity @@ -22,13 +29,48 @@ except ImportError: LINTER_POSITION_CODEC = LinterPositionCodec() +class LintWrapper: + + def __init__( + self, + path: str, + handler: Callable[[LintState], Optional[List[Diagnostic]]], + debputy_plugin_feature_set: PluginProvidedFeatureSet, + dctrl_parser: DctrlParser, + ) -> None: + self._debputy_plugin_feature_set = debputy_plugin_feature_set + self._handler = handler + self.dctrl_lines: Optional[List[str]] = None + self.path = path + self._dctrl_parser = dctrl_parser + + def __call__(self, lines: List[str]) -> Optional[List["Diagnostic"]]: + source_package = None + binary_packages = None + dctrl_lines = self.dctrl_lines + if dctrl_lines is not None: + source_package, binary_packages = ( + self._dctrl_parser.parse_source_debian_control( + dctrl_lines, ignore_errors=True + ) + ) + state = LintStateImpl( + self._debputy_plugin_feature_set, + self.path, + lines, + source_package, + binary_packages, + ) + return check_diagnostics(self._handler(state)) + + def requires_levenshtein(func: Any) -> Any: return pytest.mark.skipif( not HAS_LEVENSHTEIN, reason="Missing python3-levenshtein" )(func) -def _check_diagnostics( +def check_diagnostics( diagnostics: Optional[List["Diagnostic"]], ) -> Optional[List["Diagnostic"]]: if diagnostics: @@ -37,18 +79,6 @@ def _check_diagnostics( return diagnostics -def run_linter( - path: str, lines: List[str], linter: LinterImpl -) -> Optional[List["Diagnostic"]]: - uri = f"file://{path}" - return _check_diagnostics(linter(uri, path, lines, LINTER_POSITION_CODEC)) - - -def exactly_one_diagnostic(diagnostics: Optional[List["Diagnostic"]]) -> "Diagnostic": - assert diagnostics and len(diagnostics) == 1 - return diagnostics[0] - - def by_range_sort_key(diagnostic: Diagnostic) -> Any: start_pos = diagnostic.range.start end_pos = diagnostic.range.end diff --git a/tests/lint_tests/test_lint_changelog.py b/tests/lint_tests/test_lint_changelog.py new file mode 100644 index 0000000..25dac0e --- /dev/null +++ b/tests/lint_tests/test_lint_changelog.py @@ -0,0 +1,90 @@ +import textwrap +from typing import List, Optional + +import pytest + +from debputy.lsp.lsp_debian_changelog import _lint_debian_changelog +from debputy.lsp.lsp_debian_control import _lint_debian_control +from debputy.packages import DctrlParser +from debputy.plugin.api.feature_set import PluginProvidedFeatureSet +from lint_tests.lint_tutil import ( + group_diagnostics_by_severity, + requires_levenshtein, + LintWrapper, +) + +try: + from lsprotocol.types import Diagnostic, DiagnosticSeverity +except ImportError: + pass + + +@pytest.fixture +def line_linter( + debputy_plugin_feature_set: PluginProvidedFeatureSet, + lint_dctrl_parser: DctrlParser, +) -> LintWrapper: + return LintWrapper( + "/nowhere/debian/changelog", + _lint_debian_changelog, + debputy_plugin_feature_set, + lint_dctrl_parser, + ) + + +def test_dctrl_lint(line_linter: LintWrapper) -> None: + lines = textwrap.dedent( + """\ + foo (0.2) unstable; urgency=medium + + * Renamed to foo + + -- Niels Thykier <niels@thykier.net> Mon, 08 Apr 2024 16:00:00 +0000 + + bar (0.2) unstable; urgency=medium + + * Initial release + + -- Niels Thykier <niels@thykier.net> Mon, 01 Apr 2024 00:00:00 +0000 + """ + ).splitlines(keepends=True) + + diagnostics = line_linter(lines) + print(diagnostics) + # Without a control file, this is fine + assert not diagnostics + + line_linter.dctrl_lines = textwrap.dedent( + """\ + Source: foo + + Package: something-else + """ + ) + + diagnostics = line_linter(lines) + print(diagnostics) + # Also fine, because d/control and d/changelog agrees + assert not diagnostics + + line_linter.dctrl_lines = textwrap.dedent( + """\ + Source: bar + + Package: something-else + """ + ) + + diagnostics = line_linter(lines) + print(diagnostics) + # This should be problematic though + assert diagnostics and len(diagnostics) == 1 + diag = diagnostics[0] + + msg = ( + "The first entry must use the same source name as debian/control." + ' Changelog uses: "foo" while d/control uses: "bar"' + ) + assert diag.severity == DiagnosticSeverity.Error + assert diag.message == msg + assert f"{diag.range}" == "0:0-0:3" diff --git a/tests/lint_tests/test_lint_dctrl.py b/tests/lint_tests/test_lint_dctrl.py index cc2758e..e9a5756 100644 --- a/tests/lint_tests/test_lint_dctrl.py +++ b/tests/lint_tests/test_lint_dctrl.py @@ -1,14 +1,15 @@ import textwrap -from typing import List, Optional, Callable +from typing import List, Optional import pytest from debputy.lsp.lsp_debian_control import _lint_debian_control +from debputy.packages import DctrlParser +from debputy.plugin.api.feature_set import PluginProvidedFeatureSet from lint_tests.lint_tutil import ( - run_linter, group_diagnostics_by_severity, requires_levenshtein, - exactly_one_diagnostic, + LintWrapper, ) try: @@ -17,20 +18,30 @@ except ImportError: pass -TestLinter = Callable[[List[str]], Optional[List["Diagnostic"]]] +class DctrlLintWrapper(LintWrapper): + def __call__(self, lines: List[str]) -> Optional[List["Diagnostic"]]: + try: + self.dctrl_lines = lines + return super().__call__(lines) + finally: + self.dctrl_lines = None -@pytest.fixture -def line_linter() -> TestLinter: - path = "/nowhere/debian/control" - - def _linter(lines: List[str]) -> Optional[List["Diagnostic"]]: - return run_linter(path, lines, _lint_debian_control) - - return _linter - -def test_dctrl_lint(line_linter: TestLinter) -> None: +@pytest.fixture +def line_linter( + debputy_plugin_feature_set: PluginProvidedFeatureSet, + lint_dctrl_parser: DctrlParser, +) -> LintWrapper: + return DctrlLintWrapper( + "/nowhere/debian/control", + _lint_debian_control, + debputy_plugin_feature_set, + lint_dctrl_parser, + ) + + +def test_dctrl_lint(line_linter: LintWrapper) -> None: lines = textwrap.dedent( """\ Source: foo @@ -86,7 +97,7 @@ def test_dctrl_lint(line_linter: TestLinter) -> None: @requires_levenshtein -def test_dctrl_lint_typos(line_linter: TestLinter) -> None: +def test_dctrl_lint_typos(line_linter: LintWrapper) -> None: lines = textwrap.dedent( """\ Source: foo @@ -109,9 +120,109 @@ def test_dctrl_lint_typos(line_linter: TestLinter) -> None: diagnostics = line_linter(lines) print(diagnostics) - diag = exactly_one_diagnostic(diagnostics) + assert diagnostics and len(diagnostics) == 1 + diag = diagnostics[0] msg = 'The "Build-Dpends" looks like a typo of "Build-Depends".' assert diag.message == msg assert diag.severity == DiagnosticSeverity.Warning assert f"{diag.range}" == "6:0-6:12" + + +@requires_levenshtein +def test_dctrl_lint_mx_value_with_typo(line_linter: LintWrapper) -> None: + lines = textwrap.dedent( + """\ + Source: foo + Standards-Version: 4.5.2 + Priority: optional + Section: devel + Maintainer: Jane Developer <jane@example.com> + Build-Depends: debhelper-compat (= 13) + + Package: foo + # Typo of `all` + Architecture: linux-any alle + Description: Some very interesting synopsis + A very interesting description + that spans multiple lines + . + Just so be clear, this is for a test. + """ + ).splitlines(keepends=True) + + diagnostics = line_linter(lines) + print(diagnostics) + assert len(diagnostics) == 2 + by_severity = group_diagnostics_by_severity(diagnostics) + assert DiagnosticSeverity.Error in by_severity + assert DiagnosticSeverity.Warning in by_severity + + typo_diag = by_severity[DiagnosticSeverity.Warning][0] + mx_diag = by_severity[DiagnosticSeverity.Error][0] + mx_msg = 'The value "all" cannot be used with other values.' + typo_msg = 'It is possible that the value is a typo of "all".' + assert mx_diag.message == mx_msg + assert typo_diag.message == typo_msg + assert f"{mx_diag.range}" == "10:24-10:28" + assert f"{typo_diag.range}" == "10:24-10:28" + + +def test_dctrl_lint_mx_value(line_linter: LintWrapper) -> None: + lines = textwrap.dedent( + """\ + Source: foo + Standards-Version: 4.5.2 + Priority: optional + Section: devel + Maintainer: Jane Developer <jane@example.com> + Build-Depends: debhelper-compat (= 13) + + Package: foo + Architecture: all linux-any + Description: Some very interesting synopsis + A very interesting description + that spans multiple lines + . + Just so be clear, this is for a test. + """ + ).splitlines(keepends=True) + + diagnostics = line_linter(lines) + print(diagnostics) + assert diagnostics and len(diagnostics) == 1 + diag = diagnostics[0] + + msg = 'The value "all" cannot be used with other values.' + assert diag.message == msg + assert diag.severity == DiagnosticSeverity.Error + assert f"{diag.range}" == "8:14-8:17" + + lines = textwrap.dedent( + """\ + Source: foo + Standards-Version: 4.5.2 + Priority: optional + Section: devel + Maintainer: Jane Developer <jane@example.com> + Build-Depends: debhelper-compat (= 13) + + Package: foo + Architecture: linux-any any + Description: Some very interesting synopsis + A very interesting description + that spans multiple lines + . + Just so be clear, this is for a test. + """ + ).splitlines(keepends=True) + + diagnostics = line_linter(lines) + print(diagnostics) + assert diagnostics and len(diagnostics) == 1 + diag = diagnostics[0] + + msg = 'The value "any" cannot be used with other values.' + assert diag.message == msg + assert diag.severity == DiagnosticSeverity.Error + assert f"{diag.range}" == "8:24-8:27" diff --git a/tests/lint_tests/test_lint_debputy.py b/tests/lint_tests/test_lint_debputy.py index 74977d0..9c30392 100644 --- a/tests/lint_tests/test_lint_debputy.py +++ b/tests/lint_tests/test_lint_debputy.py @@ -1,13 +1,12 @@ -import textwrap from typing import List, Optional, Callable import pytest -from debputy.lsp.lsp_debian_debputy_manifest import _lint_debian_debputy_manifest +from debputy.packages import DctrlParser +from debputy.plugin.api.feature_set import PluginProvidedFeatureSet from lint_tests.lint_tutil import ( - run_linter, - group_diagnostics_by_severity, requires_levenshtein, + LintWrapper, ) try: @@ -16,20 +15,20 @@ except ImportError: pass -TestLinter = Callable[[List[str]], Optional[List["Diagnostic"]]] - - @pytest.fixture -def line_linter() -> TestLinter: - path = "/nowhere/debian/debputy.manifest" - - def _linter(lines: List[str]) -> Optional[List["Diagnostic"]]: - return run_linter(path, lines, _lint_debian_debputy_manifest) - - return _linter - - -def test_debputy_lint_unknown_keys(line_linter: TestLinter) -> None: +def line_linter( + debputy_plugin_feature_set: PluginProvidedFeatureSet, + lint_dctrl_parser: DctrlParser, +) -> LintWrapper: + return LintWrapper( + "/nowhere/debian/debputy.manifest", + _lint_debian_debputy_manifest, + debputy_plugin_feature_set, + lint_dctrl_parser, + ) + + +def test_debputy_lint_unknown_keys(line_linter: LintWrapper) -> None: lines = textwrap.dedent( """\ manifest-version: 0.1 @@ -85,7 +84,7 @@ def test_debputy_lint_unknown_keys(line_linter: TestLinter) -> None: @requires_levenshtein -def test_debputy_lint_unknown_keys_spelling(line_linter: TestLinter) -> None: +def test_debputy_lint_unknown_keys_spelling(line_linter: LintWrapper) -> None: lines = textwrap.dedent( """\ manifest-version: 0.1 @@ -131,7 +130,7 @@ def test_debputy_lint_unknown_keys_spelling(line_linter: TestLinter) -> None: assert f"{third_error.range}" == "8:6-8:9" -def test_debputy_lint_conflicting_keys(line_linter: TestLinter) -> None: +def test_debputy_lint_conflicting_keys(line_linter: LintWrapper) -> None: lines = textwrap.dedent( """\ manifest-version: 0.1 @@ -179,3 +178,173 @@ def test_debputy_lint_conflicting_keys(line_linter: TestLinter) -> None: msg = 'The "sources" cannot be used with "source".' assert fourth_error.message == msg assert f"{fourth_error.range}" == "9:4-9:11" + + +import textwrap +from typing import List, Optional, Callable + +import pytest + +from debputy.lsp.lsp_debian_debputy_manifest import _lint_debian_debputy_manifest +from debputy.packages import DctrlParser +from debputy.plugin.api.feature_set import PluginProvidedFeatureSet +from lint_tests.lint_tutil import ( + group_diagnostics_by_severity, + requires_levenshtein, + LintWrapper, +) + +try: + from lsprotocol.types import Diagnostic, DiagnosticSeverity +except ImportError: + pass + +TestLintWrapper = Callable[[List[str]], Optional[List["Diagnostic"]]] + + +@pytest.fixture +def line_linter( + debputy_plugin_feature_set: PluginProvidedFeatureSet, + lint_dctrl_parser: DctrlParser, +) -> LintWrapper: + return LintWrapper( + "/nowhere/debian/debputy.manifest", + _lint_debian_debputy_manifest, + debputy_plugin_feature_set, + lint_dctrl_parser, + ) + + +def test_debputy_lint_unknown_keys(line_linter: LintWrapper) -> None: + lines = textwrap.dedent( + """\ + manifest-version: 0.1 + installations: + - install-something: + sources: + - abc + - def + - install-docs: + source: foo + puff: true # Unknown keyword (assuming install-docs) + when: + negated: cross-compiling + - install-docs: + source: bar + when: ross-compiling # Typo of "cross-compiling"; FIXME not caught + packages: + foo: + blah: qwe # Unknown keyword + """ + ).splitlines(keepends=True) + + diagnostics = line_linter(lines) + by_severity = group_diagnostics_by_severity(diagnostics) + # This example triggers errors only + assert DiagnosticSeverity.Error in by_severity + + assert DiagnosticSeverity.Warning not in by_severity + assert DiagnosticSeverity.Hint not in by_severity + assert DiagnosticSeverity.Information not in by_severity + + errors = by_severity[DiagnosticSeverity.Error] + print(errors) + assert len(errors) == 4 + + first_error, second_error, third_error, fourth_error = errors + + msg = 'Unknown or unsupported key "install-something".' + assert first_error.message == msg + assert f"{first_error.range}" == "2:2-2:19" + + msg = 'Unknown or unsupported key "puff".' + assert second_error.message == msg + assert f"{second_error.range}" == "8:4-8:8" + + msg = 'Unknown or unsupported key "negated".' + assert third_error.message == msg + assert f"{third_error.range}" == "10:6-10:13" + + msg = 'Unknown or unsupported key "blah".' + assert fourth_error.message == msg + assert f"{fourth_error.range}" == "16:4-16:8" + + +@requires_levenshtein +def test_debputy_lint_unknown_keys_spelling(line_linter: LintWrapper) -> None: + lines = textwrap.dedent( + """\ + manifest-version: 0.1 + installations: + - install-dcoss: # typo + sources: + - abc + - def + puff: true # Unknown keyword (assuming install-docs) + when: + nut: cross-compiling # Typo of "not" + - install-docs: + source: bar + when: ross-compiling # Typo of "cross-compiling"; FIXME not caught + """ + ).splitlines(keepends=True) + + diagnostics = line_linter(lines) + by_severity = group_diagnostics_by_severity(diagnostics) + # This example triggers errors only + assert DiagnosticSeverity.Error in by_severity + + assert DiagnosticSeverity.Warning not in by_severity + assert DiagnosticSeverity.Hint not in by_severity + assert DiagnosticSeverity.Information not in by_severity + + errors = by_severity[DiagnosticSeverity.Error] + print(errors) + assert len(errors) == 3 + + first_error, second_error, third_error = errors + + msg = 'Unknown or unsupported key "install-dcoss". It looks like a typo of "install-docs".' + assert first_error.message == msg + assert f"{first_error.range}" == "2:2-2:15" + + msg = 'Unknown or unsupported key "puff".' + assert second_error.message == msg + assert f"{second_error.range}" == "6:4-6:8" + + msg = 'Unknown or unsupported key "nut". It looks like a typo of "not".' + assert third_error.message == msg + assert f"{third_error.range}" == "8:6-8:9" + + +def test_debputy_lint_check_package_names(line_linter: LintWrapper) -> None: + lines = textwrap.dedent( + """\ + manifest-version: 0.1 + packages: + unknown-package: + binary-version: '1:{{DEB_VERSION_UPSTREAM_REVISION}}' + """ + ).splitlines(keepends=True) + + line_linter.dctrl_lines = None + diagnostics = line_linter(lines) + print(diagnostics) + # Does nothing without a control file + assert not diagnostics + + line_linter.dctrl_lines = textwrap.dedent( + """\ + Source: foo + + Package: foo + """ + ).splitlines(keepends=True) + + diagnostics = line_linter(lines) + assert diagnostics and len(diagnostics) == 1 + diag = diagnostics[0] + + msg = 'Unknown package "unknown-package".' + assert diag.message == msg + assert f"{diag.range}" == "2:4-2:19" diff --git a/tests/lsp_tests/conftest.py b/tests/lsp_tests/conftest.py index ec12e9a..e995d88 100644 --- a/tests/lsp_tests/conftest.py +++ b/tests/lsp_tests/conftest.py @@ -1,5 +1,9 @@ import pytest +from debian.debian_support import DpkgArchTable +from debputy._deb_options_profiles import DebBuildOptionsAndProfiles +from debputy.architecture_support import DpkgArchitectureBuildProcessValuesTable +from debputy.packages import DctrlParser from debputy.plugin.api.feature_set import PluginProvidedFeatureSet from debputy.util import setup_logging @@ -17,7 +21,7 @@ try: HoverParams, MarkupContent, ) - from debputy.lsp.lsp_features import lsp_set_plugin_features + from debputy.lsp.debputy_ls import DebputyLanguageServer HAS_PYGLS = True except ImportError: @@ -29,13 +33,31 @@ def enable_logging() -> None: setup_logging(log_only_to_stderr=True, reconfigure_logging=True) +@pytest.fixture +def lsp_dctrl_parser( + dpkg_arch_query: DpkgArchTable, + amd64_dpkg_architecture_variables: DpkgArchitectureBuildProcessValuesTable, + no_profiles_or_build_options: DebBuildOptionsAndProfiles, +) -> DctrlParser: + return DctrlParser( + frozenset(), + frozenset(), + True, + True, + amd64_dpkg_architecture_variables, + dpkg_arch_query, + no_profiles_or_build_options, + ) + + @pytest.fixture() def ls( debputy_plugin_feature_set: PluginProvidedFeatureSet, -) -> "LanguageServer": + lsp_dctrl_parser: DctrlParser, +) -> "DebputyLanguageServer": if not HAS_PYGLS: pytest.skip("Missing pygls") - ls = LanguageServer("debputy", "v<test>") + ls = DebputyLanguageServer("debputy", "v<test>") ls.lsp.lsp_initialize( InitializeParams( ClientCapabilities( @@ -45,8 +67,6 @@ def ls( ) ) ) - lsp_set_plugin_features(debputy_plugin_feature_set) - try: - yield ls - finally: - lsp_set_plugin_features(None) + ls.plugin_feature_set = debputy_plugin_feature_set + ls.dctrl_parser = lsp_dctrl_parser + return ls diff --git a/tests/lsp_tests/lsp_tutil.py b/tests/lsp_tests/lsp_tutil.py index 2873f72..0843f79 100644 --- a/tests/lsp_tests/lsp_tutil.py +++ b/tests/lsp_tests/lsp_tutil.py @@ -1,4 +1,4 @@ -from typing import Tuple +from typing import Tuple, Union try: from pygls.server import LanguageServer @@ -6,6 +6,7 @@ try: TextDocumentItem, Position, ) + from debputy.lsp.debputy_ls import DebputyLanguageServer except ImportError: pass @@ -26,7 +27,7 @@ def _locate_cursor(text: str) -> Tuple[str, "Position"]: def put_doc_with_cursor( - ls: "LanguageServer", + ls: Union["LanguageServer", "DebputyLanguageServer"], uri: str, language_id: str, content: str, diff --git a/tests/lsp_tests/test_lsp_dctrl.py b/tests/lsp_tests/test_lsp_dctrl.py index d258e8f..122b929 100644 --- a/tests/lsp_tests/test_lsp_dctrl.py +++ b/tests/lsp_tests/test_lsp_dctrl.py @@ -70,3 +70,91 @@ def test_dctrl_hover_doc_field(ls: "LanguageServer") -> None: ) assert hover_doc is not None and isinstance(hover_doc.contents, MarkupContent) assert "Determines which architecture" in hover_doc.contents.value + + +def test_dctrl_hover_doc_synopsis(ls: "LanguageServer") -> None: + dctrl_uri = "file:///nowhere/debian/control" + cursor_pos = put_doc_with_cursor( + ls, + dctrl_uri, + "debian/control", + textwrap.dedent( + """\ + Source: foo + + Package: foo + Architecture: any + Description: super charged<CURSOR> tool with batteries included +""" + ), + ) + + hover_doc = _debian_control_hover( + ls, + HoverParams(TextDocumentIdentifier(dctrl_uri), cursor_pos), + ) + assert hover_doc is not None and isinstance(hover_doc.contents, MarkupContent) + assert hover_doc.contents.value.startswith("# Package synopsis") + assert "super charged tool with batteries included" in hover_doc.contents.value + + +def test_dctrl_hover_doc_substvars(ls: "LanguageServer") -> None: + dctrl_uri = "file:///nowhere/debian/control" + matching_cases = [ + "bar (= <CURSOR>${binary:Version})", + "bar (= $<CURSOR>{binary:Version})", + "bar (= ${binary:Version<CURSOR>})", + ] + for variant in matching_cases: + cursor_pos = put_doc_with_cursor( + ls, + dctrl_uri, + "debian/control", + textwrap.dedent( + f"""\ + Source: foo + + Package: foo + Architecture: any + Depends: bar (= {variant}) + Description: super charged tool with batteries included + """ + ), + ) + + hover_doc = _debian_control_hover( + ls, + HoverParams(TextDocumentIdentifier(dctrl_uri), cursor_pos), + ) + assert hover_doc is not None and isinstance(hover_doc.contents, MarkupContent) + assert hover_doc.contents.value.startswith("# Substvar `${binary:Version}`") + + non_matching_cases = [ + "bar (=<CURSOR> ${binary:Version})", + "bar (= ${binary:Version}<CURSOR>)", + ] + for variant in non_matching_cases: + cursor_pos = put_doc_with_cursor( + ls, + dctrl_uri, + "debian/control", + textwrap.dedent( + f"""\ + Source: foo + + Package: foo + Architecture: any + Depends: bar (= {variant}) + Description: super charged tool with batteries included + """ + ), + ) + + hover_doc = _debian_control_hover( + ls, + HoverParams(TextDocumentIdentifier(dctrl_uri), cursor_pos), + ) + provided_doc = "" + if hover_doc is not None and isinstance(hover_doc.contents, MarkupContent): + provided_doc = hover_doc.contents.value + assert not provided_doc.startswith("# Substvar `${binary:Version}`") diff --git a/tests/lsp_tests/test_lsp_debputy_manifest_completer.py b/tests/lsp_tests/test_lsp_debputy_manifest_completer.py index c72e791..196df2e 100644 --- a/tests/lsp_tests/test_lsp_debputy_manifest_completer.py +++ b/tests/lsp_tests/test_lsp_debputy_manifest_completer.py @@ -1,7 +1,5 @@ import textwrap -import pytest - from lsp_tests.lsp_tutil import put_doc_with_cursor try: @@ -19,13 +17,14 @@ try: MarkupContent, ) from debputy.lsp.lsp_debian_debputy_manifest import debputy_manifest_completer + from debputy.lsp.debputy_ls import DebputyLanguageServer HAS_PYGLS = True except ImportError: HAS_PYGLS = False -def test_basic_debputy_completer_empty(ls: "LanguageServer") -> None: +def test_basic_debputy_completer_empty(ls: "DebputyLanguageServer") -> None: debputy_manifest_uri = "file:///nowhere/debian/debputy.manifest" cursor_pos = put_doc_with_cursor( ls, @@ -187,7 +186,9 @@ def test_basic_debputy_completer_empty(ls: "LanguageServer") -> None: assert "packages:" not in keywords -def test_basic_debputy_completer_manifest_variable_value(ls: "LanguageServer") -> None: +def test_basic_debputy_completer_manifest_variable_value( + ls: "DebputyLanguageServer", +) -> None: debputy_manifest_uri = "file:///nowhere/debian/debputy.manifest" cursor_pos = put_doc_with_cursor( ls, @@ -229,7 +230,7 @@ def test_basic_debputy_completer_manifest_variable_value(ls: "LanguageServer") - def test_basic_debputy_completer_install_rule_dispatch_key( - ls: "LanguageServer", + ls: "DebputyLanguageServer", ) -> None: debputy_manifest_uri = "file:///nowhere/debian/debputy.manifest" cursor_pos = put_doc_with_cursor( @@ -280,7 +281,7 @@ def test_basic_debputy_completer_install_rule_dispatch_key( def test_basic_debputy_completer_install_rule_install_keys( - ls: "LanguageServer", + ls: "DebputyLanguageServer", ) -> None: debputy_manifest_uri = "file:///nowhere/debian/debputy.manifest" cursor_pos = put_doc_with_cursor( @@ -339,7 +340,7 @@ def test_basic_debputy_completer_install_rule_install_keys( def test_basic_debputy_completer_packages_foo( - ls: "LanguageServer", + ls: "DebputyLanguageServer", ) -> None: debputy_manifest_uri = "file:///nowhere/debian/debputy.manifest" @@ -368,7 +369,7 @@ def test_basic_debputy_completer_packages_foo( def test_basic_debputy_completer_packages_foo_xfail( - ls: "LanguageServer", + ls: "DebputyLanguageServer", ) -> None: debputy_manifest_uri = "file:///nowhere/debian/debputy.manifest" cursor_pos = put_doc_with_cursor( @@ -396,7 +397,7 @@ def test_basic_debputy_completer_packages_foo_xfail( def test_basic_debputy_completer_services_service_scope_values( - ls: "LanguageServer", + ls: "DebputyLanguageServer", ) -> None: debputy_manifest_uri = "file:///nowhere/debian/debputy.manifest" @@ -497,7 +498,7 @@ def test_basic_debputy_completer_services_service_scope_values( def test_basic_debputy_completer_manifest_conditions( - ls: "LanguageServer", + ls: "DebputyLanguageServer", ) -> None: debputy_manifest_uri = "file:///nowhere/debian/debputy.manifest" |