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
|
"""Test the codeclimate JSON formatter."""
from __future__ import annotations
import json
import pathlib
import subprocess
import sys
import pytest
from ansiblelint.app import get_app
from ansiblelint.errors import MatchError
from ansiblelint.file_utils import Lintable
from ansiblelint.formatters import CodeclimateJSONFormatter
from ansiblelint.rules import AnsibleLintRule, RulesCollection
class TestCodeclimateJSONFormatter:
"""Unit test for CodeclimateJSONFormatter."""
rule = AnsibleLintRule()
matches: list[MatchError] = []
formatter: CodeclimateJSONFormatter | None = None
collection = RulesCollection(app=get_app(offline=True))
def setup_class(self) -> None:
"""Set up few MatchError objects."""
self.rule = AnsibleLintRule()
self.rule.id = "TCF0001"
self.rule.severity = "VERY_HIGH"
self.collection.register(self.rule)
self.matches = []
self.matches.append(
MatchError(
message="message",
lineno=1,
details="hello",
lintable=Lintable("filename.yml", content=""),
rule=self.rule,
),
)
self.matches.append(
MatchError(
message="message",
lineno=2,
details="hello",
lintable=Lintable("filename.yml", content=""),
rule=self.rule,
ignored=True,
),
)
self.formatter = CodeclimateJSONFormatter(
pathlib.Path.cwd(),
display_relative_path=True,
)
def test_json_format_list(self) -> None:
"""Test if the return value is a string."""
assert isinstance(self.formatter, CodeclimateJSONFormatter)
assert isinstance(self.formatter.format_result(self.matches), str)
def test_result_is_json(self) -> None:
"""Test if returned string value is a JSON."""
assert isinstance(self.formatter, CodeclimateJSONFormatter)
output = self.formatter.format_result(self.matches)
json.loads(output)
# https://github.com/ansible/ansible-navigator/issues/1490
assert "\n" not in output
def test_json_single_match(self) -> None:
"""Test negative case. Only lists are allowed. Otherwise a RuntimeError will be raised."""
assert isinstance(self.formatter, CodeclimateJSONFormatter)
with pytest.raises(TypeError):
self.formatter.format_result(self.matches[0]) # type: ignore[arg-type]
def test_result_is_list(self) -> None:
"""Test if the return JSON contains a list with a length of 2."""
assert isinstance(self.formatter, CodeclimateJSONFormatter)
result = json.loads(self.formatter.format_result(self.matches))
assert len(result) == 2
def test_validate_codeclimate_schema(self) -> None:
"""Test if the returned JSON is a valid codeclimate report."""
assert isinstance(self.formatter, CodeclimateJSONFormatter)
result = json.loads(self.formatter.format_result(self.matches))
single_match = result[0]
assert "type" in single_match
assert single_match["type"] == "issue"
assert "check_name" in single_match
assert "categories" in single_match
assert isinstance(single_match["categories"], list)
assert "severity" in single_match
assert single_match["severity"] == "major"
assert "description" in single_match
assert "fingerprint" in single_match
assert "location" in single_match
assert "path" in single_match["location"]
assert single_match["location"]["path"] == self.matches[0].filename
assert "lines" in single_match["location"]
assert single_match["location"]["lines"]["begin"] == self.matches[0].lineno
assert "positions" not in single_match["location"]
# check that the 2nd match is marked as 'minor' because it was created with ignored=True
assert result[1]["severity"] == "minor"
def test_validate_codeclimate_schema_with_positions(self) -> None:
"""Test if the returned JSON is a valid codeclimate report (containing 'positions' instead of 'lines')."""
assert isinstance(self.formatter, CodeclimateJSONFormatter)
result = json.loads(
self.formatter.format_result(
[
MatchError(
message="message",
lineno=1,
column=42,
details="hello",
lintable=Lintable("filename.yml", content=""),
rule=self.rule,
),
],
),
)
assert result[0]["location"]["positions"]["begin"]["line"] == 1
assert result[0]["location"]["positions"]["begin"]["column"] == 42
assert "lines" not in result[0]["location"]
def test_code_climate_parsable_ignored() -> None:
"""Test that -p option does not alter codeclimate format."""
cmd = [
sys.executable,
"-m",
"ansiblelint",
"-v",
"-p",
]
file = "examples/playbooks/empty_playbook.yml"
result = subprocess.run([*cmd, file], check=False)
result2 = subprocess.run([*cmd, "-p", file], check=False)
assert result.returncode == result2.returncode
assert result.stdout == result2.stdout
|