Example #1
0
    def test_get_enabled_policies_with_a_disabled_option(self):
        config_dict = {
            'cmdargs': {
                'severity': Level.WARNING,
            },
            'policies': {
                'PolicyFixture1': {
                    'enabled': True,
                },
                'PolicyFixture2': {
                    'enabled': False,
                },
            }
        }

        policy_set = PolicySet()
        policy_set.update_by_config(config_dict)

        actual_enabled_policies = policy_set.get_enabled_policies()

        expected_enabled_policy_classes = [
            PolicyFixture1,
        ]

        self.assertEnabledPolicies(expected_enabled_policy_classes, actual_enabled_policies)
Example #2
0
    def test_get_enabled_policies_with_a_disabled_option(self):
        config_dict = {
            'cmdargs': {
                'severity': Level.WARNING,
            },
            'policies': {
                'PolicyFixture1': {
                    'enabled': True,
                },
                'PolicyFixture2': {
                    'enabled': False,
                },
            }
        }

        policy_set = PolicySet([PolicyFixture1, PolicyFixture2])
        policy_set.update_by_config(config_dict)

        actual_enabled_policies = policy_set.get_enabled_policies()

        expected_enabled_policy_classes = [
            PolicyFixture1,
        ]

        self.assertEnabledPolicies(expected_enabled_policy_classes,
                                   actual_enabled_policies)
Example #3
0
    def assertFoundViolationsEqual(self,
                                   path,
                                   Policy,
                                   expected_violations,
                                   policy_options=None):
        policy_name = Policy.__name__
        policy_set = PolicySet([Policy])

        config_dict = {
            'cmdargs': {
                'severity': Level.STYLE_PROBLEM,
            },
            'policies': {
                policy_name: {
                    'enabled': True,
                }
            },
        }

        if policy_options is not None:
            config_dict['policies'][policy_name] = policy_options

        linter = Linter(policy_set, config_dict)
        violations = linter.lint(LintTargetFile(path))

        pprint(violations)
        self.assertEqual(len(violations), len(expected_violations))

        for violation, expected_violation in zip_longest(
                violations, expected_violations):
            self.assertViolation(violation, expected_violation)
Example #4
0
    def test_get_enabled_policies_with_severity_warning(self):
        config_dict = {
            'cmdargs': {
                'severity': Level.WARNING,
            },
            'policies': {}
        }

        policy_set = PolicySet()
        policy_set.update_by_config(config_dict)

        actual_enabled_policies = policy_set.get_enabled_policies()

        expected_enabled_policy_classes = [
            PolicyFixture1,
        ]

        self.assertEnabledPolicies(expected_enabled_policy_classes, actual_enabled_policies)
Example #5
0
    def test_get_enabled_policies_with_severity_style_problem(self):
        config_dict = {
            'cmdargs': {
                'severity': Level.STYLE_PROBLEM,
            },
            'policies': {}
        }

        policy_set = PolicySet()
        policy_set.update_by_config(config_dict)

        actual_enabled_policies = policy_set.get_enabled_policies()

        expected_enabled_policy_classes = [
            PolicyFixture1,
            PolicyFixture2,
        ]

        self.assertEnabledPolicies(expected_enabled_policy_classes, actual_enabled_policies)
Example #6
0
    def test_get_enabled_policies_with_severity_warning(self):
        config_dict = {
            'cmdargs': {
                'severity': Level.WARNING,
            },
            'policies': {}
        }

        policy_set = PolicySet([PolicyFixture1, PolicyFixture2])
        policy_set.update_by_config(config_dict)

        actual_enabled_policies = policy_set.get_enabled_policies()

        expected_enabled_policy_classes = [
            PolicyFixture1,
        ]

        self.assertEnabledPolicies(expected_enabled_policy_classes,
                                   actual_enabled_policies)
Example #7
0
    def test_get_enabled_policies(self):
        policy_enabling_map_to_enable_policy1 = {
            'PolicyFixture1': {
                'enabled': True,
            },
            'PolicyFixture2': {
                'enabled': False,
            },
        }

        policy_set = PolicySet()
        policy_set.update_by_config(policy_enabling_map_to_enable_policy1)

        expected_policy1_to_be_enabled = policy_set.get_enabled_policies()
        self.assertEqual(len(expected_policy1_to_be_enabled), 1,
                         'Expect number of enabled policies to equal 1')

        from test.fixture.policy_set.policy_fixture_1 import PolicyFixture1
        self.assertIsInstance(expected_policy1_to_be_enabled[0], PolicyFixture1,
                              'Expect policy1 to be enabled')
Example #8
0
    def test_get_enabled_policies(self):
        policy_enabling_map_to_enable_policy1 = {
            'PolicyFixture1': {
                'enabled': True,
            },
            'PolicyFixture2': {
                'enabled': False,
            },
        }

        policy_set = PolicySet()
        policy_set.update_by_config(policy_enabling_map_to_enable_policy1)

        expected_policy1_to_be_enabled = policy_set.get_enabled_policies()
        self.assertEqual(len(expected_policy1_to_be_enabled), 1,
                         'Expect number of enabled policies to equal 1')

        from test.fixture.policy_set.policy_fixture_1 import PolicyFixture1
        self.assertIsInstance(expected_policy1_to_be_enabled[0],
                              PolicyFixture1, 'Expect policy1 to be enabled')
Example #9
0
    def test_get_enabled_policies_with_severity_style_problem(self):
        config_dict = {
            'cmdargs': {
                'severity': Level.STYLE_PROBLEM,
            },
            'policies': {}
        }

        policy_set = PolicySet([PolicyFixture1, PolicyFixture2])
        policy_set.update_by_config(config_dict)

        actual_enabled_policies = policy_set.get_enabled_policies()

        expected_enabled_policy_classes = [
            PolicyFixture1,
            PolicyFixture2,
        ]

        self.assertEnabledPolicies(expected_enabled_policy_classes,
                                   actual_enabled_policies)
    def test_simple_example(self):
        global_config_dict = {'cmdargs': {'severity': Level.ERROR}}
        policy_set = PolicySet([TestConfigNextLineCommentSource.ProhibitStringPolicy])
        linter = Linter(policy_set, global_config_dict)
        lint_target = LintTargetFile(Fixtures.SIMPLE.value)

        reported_string_node_values = [violation['description']
                                       for violation in linter.lint(lint_target)]

        self.assertEqual(reported_string_node_values, [
            "'report me because I have no line config comments'",
            "'report me because I have no line config comments, but the previous line have it'",
        ])
    def test_lambda_string_expr(self):
        global_config_dict = {'cmdargs': {'severity': Level.ERROR}}
        policy_set = PolicySet([TestConfigNextLineCommentSource.ProhibitStringPolicy])
        linter = Linter(policy_set, global_config_dict)
        lint_target = LintTargetFile(Fixtures.LAMBDA_STRING_EXPR.value)

        reported_string_node_values = [violation['description']
                                       for violation in linter.lint(lint_target)]

        self.assertEqual(reported_string_node_values, [
            "'report me because I have no line config comments'",
            "'report me because I have no line config comments, but the previous line have it'",
            # NOTE: In the current implementation, string in string will reported twice.
            "'\"report me because I have no line config comments, but the parent node have it\"'",
            '"report me because I have no line config comments, but the parent node have it"',
        ])
Example #12
0
    def rpc_lsp_formatter_vint(self, args: List[Any]) -> Any:
        buf_path: Optional[str]
        buf_root_dir: str
        buf_lines: List[str]
        buf_path, buf_root_dir, buf_lines = args

        try:
            from vint.bootstrap import init_linter
            from vint.linting.env import build_environment
            from vint.linting.config.config_container import ConfigContainer
            from vint.linting.config.config_cmdargs_source import ConfigCmdargsSource
            from vint.linting.config.config_default_source import ConfigDefaultSource
            from vint.linting.config.config_global_source import ConfigGlobalSource
            from vint.linting.config.config_project_source import ConfigProjectSource
            from vint.linting.policy_set import PolicySet
            from vint.linting.linter import Linter
        except ModuleNotFoundError as err:
            raise pynvim.ErrorResponse('vint is not installed: {}'.format(err))

        init_linter()

        lint_file_path = Path(buf_path if buf_path is not None else os.devnull)
        # The codebase seems to always check for presence of keys in `cmdargs`,
        # possibly because they can be specified as an dictionary in a config file,
        # as such construction of a realistic dictionary is not necessary.
        # lint_cmdargs = vars(vint.linting.cli.CLI()._build_argparser().parse_args([]))
        lint_cmdargs = {
            # Stub for v0.4a1 and later, see below.
            'stdin_display_name': str(lint_file_path)
        }
        lint_env: Dict[str, Any] = build_environment(lint_cmdargs)
        lint_env['cwd'] = Path(buf_root_dir)
        lint_env['file_paths'] = ['-'
                                  ]  # Basically a stub but is not read at all.

        config = ConfigContainer(
            ConfigDefaultSource(lint_env),
            ConfigGlobalSource(lint_env),
            ConfigProjectSource(lint_env),
            ConfigCmdargsSource(lint_env),
        )
        config_dict: Any = config.get_config_dict()

        # TODO: same comment
        buf_text = '\n'.join(buf_lines) + '\n'

        # Alright, so, here's the deal... We can't use `lint_text` directly. That
        # is because in all versions since 0.2.0 there is this policy
        # `MissingScriptEncoding` which attempts to read the file to check its
        # encoding. `lint_text` is normally called when the linted file is supplied
        # via stdin, then the `Linter` class sets the path of the file to the
        # special string `stdin` (Note: relax, this will not lead to hilarious bugs
        # when linting a legitimate file named `stdin`, this is not Javascript with
        # its lazy comparison rules, real paths are instances of the `pathlib.Path`
        # class), which the aforementioned policy checks to determine where to read
        # the file contents from. In our case, however, the file is supplied from a
        # string and not from a real file, and stdin is used for PRC with Nvim, so
        # this leads to a crash.
        #
        # ...However, the above problem occurs just in my bizarre Vim setup, but do
        # you know what's even better? There is another policy, `NoAbortFunction`,
        # which ensures that all functions defined in files in the `autoload`
        # directory have a `!` and `abort`... and, because it treats the path
        # parameter as a `pathlib.Path`, it will ALWAYS crash when the file is
        # supplied via stdin (like `vint - < init.vim`, which is entirely normal
        # usage of the program)! Because, of course, the special value `stdin` is
        # used. This rule was already implemented in version 0.0.0.
        #
        # Now, I can only imagine why this blatant bug has gone unnoticed for so
        # frikin long, although stdin support has not always been present, it was
        # actually added only relatively recently as part of 0.3.19:
        # <https://github.com/Vimjas/vint/commit/cac0cf731dc34ed0a3ffcf1191774d91fbfa8f89>.
        # However, what this means for me is that I have to either write the buffer
        # text to disk into a temporary file, or use the knowledge of internals and
        # write code which essentially combines both `lint_text` and `lint_file`.
        #
        # Thankfully, 0.4a1 and onwards implement a LintTarget abstraction which
        # solves this problem, but currently this version is not available in
        # Arch's repos, so there. See
        # <https://github.com/Vimjas/vint/commit/3a2729eb6a5eb809054a1357ae1e1f32bc59cb1c>.

        violations: List[Dict[str, Any]] = []

        if hasattr(Linter, 'lint'):
            # For >=0.4
            from vint.linting.policy_registry import get_policy_classes
            from vint.linting.lint_target import AbstractLintTarget

            class LintTargetInMemory(AbstractLintTarget):
                def __init__(self, path: Path, contents: bytes) -> None:
                    super().__init__(path)
                    self.contents = contents

                def read(self) -> bytes:
                    return self.contents

            policy_set = PolicySet(get_policy_classes())
            linter = Linter(policy_set, config_dict)
            violations = linter.lint(
                LintTargetInMemory(lint_file_path, buf_text.encode('utf8')))

        elif hasattr(Linter, 'lint_text'):
            # For >=0.3.19 <0.4
            from vint._bundles import vimlparser
            from vint.encodings.decoder import EncodingDetectionError
            from vint.linting.policy.prohibit_missing_scriptencoding import ProhibitMissingScriptEncoding

            policy_set = PolicySet()
            linter = Linter(policy_set, config_dict)
            linter._log_file_path_to_lint(lint_file_path)

            # However, additionally I still patch out the function which is
            # responsible for reading the file in `MissingScriptEncoding`, this is to
            # ensure that it can work on unsaved files and if the file doesn't even
            # exist. I also think that this is the cleanest way to do the
            # monkey-patch because only one instance of the policy is affected, and
            # they are always newly created in the `PolicySet`'s constructor.
            broken_policy: Any = policy_set._all_policies_map.get(
                'ProhibitMissingScriptEncoding')
            if type(broken_policy) == ProhibitMissingScriptEncoding:

                def check_script_has_multibyte_char(lint_context: Any) -> bool:
                    # <https://stackoverflow.com/a/51141941/12005228>
                    return not buf_text.isascii()

                broken_policy._check_script_has_multibyte_char = check_script_has_multibyte_char

            root_ast = None
            have_parsing_error = False
            try:
                root_ast = linter._parser.parse(buf_text)
            except vimlparser.VimLParserException as err:
                violations = [
                    linter._create_parse_error(lint_file_path, str(err))
                ]
                have_parsing_error = True
            except EncodingDetectionError as err:
                # NOTE: EncodingDetectionError can only be thrown when calling
                # `linter._parser.parse_file`, but I handle it for completeness.
                violations = [
                    linter._create_decoding_error(lint_file_path, str(err))
                ]
                have_parsing_error = True

            if not have_parsing_error:
                linter._traverse(root_ast, lint_file_path)
                violations = linter._violations

        else:
            # For <0.3.19
            policy_set = PolicySet()
            linter = Linter(policy_set, config_dict)

            # Poor man's method involving a temporary file.
            tmp_dir: Optional[str] = None
            tmp_prefix: Optional[str] = None
            tmp_suffix: Optional[str] = '.vim'
            if buf_path is not None:
                tmp_dir = os.path.dirname(buf_path)
                if not os.path.isdir(tmp_dir):
                    tmp_dir = None
                tmp_prefix, tmp_suffix = os.path.splitext(
                    os.path.basename(buf_path))

            with tempfile.NamedTemporaryFile(
                    dir=tmp_dir, prefix=tmp_prefix,
                    suffix=tmp_suffix) as tmp_buf_file:
                tmp_buf_file.write(buf_text.encode('utf8'))
                tmp_buf_file.flush()
                violations = linter.lint_file(Path(tmp_buf_file.name))

        rpc_result: List[List[Any]] = []
        for idx, violation in enumerate(violations):
            rpc_result.append([
                violation['position']['line'],
                violation['position']['column'],
                violation['level'].value,
                violation['name'],
                violation['description'],
                violation['reference'],
            ])

        return rpc_result
Example #13
0
    def test_get_enabled_policies_when_no_updated(self):
        policy_set = PolicySet()

        expected_no_policies = policy_set.get_enabled_policies()
        self.assertEqual(expected_no_policies, [],
                         'Expect all policies to be disabled')
Example #14
0
    def test_get_enabled_policies_when_no_updated(self):
        policy_set = PolicySet([PolicyFixture1, PolicyFixture2])

        expected_no_policies = policy_set.get_enabled_policies()
        self.assertEqual(expected_no_policies, [],
                         'Expect all policies to be disabled')
Example #15
0
def _build_linter(config_dict):  # type: (Dict[str, Any]) -> Linter
    policy_set = PolicySet(get_policy_classes())
    linter = Linter(policy_set, config_dict)
    return linter
Example #16
0
 def _build_linter(self, config_dict):
     policy_set = PolicySet()
     linter = Linter(policy_set, config_dict)
     return linter
 def _build_linter(self):
     env = build_environment({})
     vint_config = self._build_config_dict(env)
     policies = PolicySet()
     return Linter(policies, vint_config)