1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this
3# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5import json
6
7import attr
8
9import mozunit
10import mozpack.path as mozpath
11import pytest
12
13from mozlint.result import Issue, ResultSummary
14from mozlint import formatters
15
16NORMALISED_PATHS = {
17    "abc": mozpath.normpath("a/b/c.txt"),
18    "def": mozpath.normpath("d/e/f.txt"),
19    "root": mozpath.abspath("/fake/root"),
20}
21
22EXPECTED = {
23    "compact": {
24        "kwargs": {},
25        "format": """
26/fake/root/a/b/c.txt: line 1, Error - oh no foo (foo)
27/fake/root/a/b/c.txt: line 4, col 10, Error - oh no baz (baz)
28/fake/root/a/b/c.txt: line 5, Error - oh no foo-diff (foo-diff)
29/fake/root/d/e/f.txt: line 4, col 2, Warning - oh no bar (bar-not-allowed)
30
314 problems
32""".strip(),
33    },
34    "stylish": {
35        "kwargs": {"disable_colors": True},
36        "format": """
37/fake/root/a/b/c.txt
38  1     error  oh no foo       (foo)
39  4:10  error  oh no baz       (baz)
40  5     error  oh no foo-diff  (foo-diff)
41  diff 1
42  - hello
43  + hello2
44
45/fake/root/d/e/f.txt
46  4:2  warning  oh no bar  bar-not-allowed (bar)
47
48\u2716 4 problems (3 errors, 1 warning, 0 fixed)
49""".strip(),
50    },
51    "treeherder": {
52        "kwargs": {},
53        "format": """
54TEST-UNEXPECTED-ERROR | /fake/root/a/b/c.txt:1 | oh no foo (foo)
55TEST-UNEXPECTED-ERROR | /fake/root/a/b/c.txt:4:10 | oh no baz (baz)
56TEST-UNEXPECTED-ERROR | /fake/root/a/b/c.txt:5 | oh no foo-diff (foo-diff)
57TEST-UNEXPECTED-WARNING | /fake/root/d/e/f.txt:4:2 | oh no bar (bar-not-allowed)
58""".strip(),
59    },
60    "unix": {
61        "kwargs": {},
62        "format": """
63{abc}:1: foo error: oh no foo
64{abc}:4:10: baz error: oh no baz
65{abc}:5: foo-diff error: oh no foo-diff
66{def}:4:2: bar-not-allowed warning: oh no bar
67""".format(
68            **NORMALISED_PATHS
69        ).strip(),
70    },
71    "summary": {
72        "kwargs": {},
73        "format": """
74{root}/a: 3 errors
75{root}/d: 0 errors, 1 warning
76""".format(
77            **NORMALISED_PATHS
78        ).strip(),
79    },
80}
81
82
83@pytest.fixture
84def result(scope="module"):
85    result = ResultSummary("/fake/root")
86    containers = (
87        Issue(linter="foo", path="a/b/c.txt", message="oh no foo", lineno=1),
88        Issue(
89            linter="bar",
90            path="d/e/f.txt",
91            message="oh no bar",
92            hint="try baz instead",
93            level="warning",
94            lineno="4",
95            column="2",
96            rule="bar-not-allowed",
97        ),
98        Issue(
99            linter="baz",
100            path="a/b/c.txt",
101            message="oh no baz",
102            lineno=4,
103            column=10,
104            source="if baz:",
105        ),
106        Issue(
107            linter="foo-diff",
108            path="a/b/c.txt",
109            message="oh no foo-diff",
110            lineno=5,
111            source="if baz:",
112            diff="diff 1\n- hello\n+ hello2",
113        ),
114    )
115    result = ResultSummary("/fake/root")
116    for c in containers:
117        result.issues[c.path].append(c)
118    return result
119
120
121@pytest.mark.parametrize("name", EXPECTED.keys())
122def test_formatters(result, name):
123    opts = EXPECTED[name]
124    fmt = formatters.get(name, **opts["kwargs"])
125    # encoding to str bypasses a UnicodeEncodeError in pytest
126    assert fmt(result) == opts["format"]
127
128
129def test_json_formatter(result):
130    fmt = formatters.get("json")
131    formatted = json.loads(fmt(result))
132
133    assert set(formatted.keys()) == set(result.issues.keys())
134
135    attrs = attr.fields(Issue)
136    for errors in formatted.values():
137        for err in errors:
138            assert all(a.name in err for a in attrs)
139
140
141if __name__ == "__main__":
142    mozunit.main()
143