xref: /llvm-project/clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py (revision dd3c26a045c081620375a878159f536758baba6e)
1# -*- coding: utf-8 -*-
2# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3# See https://llvm.org/LICENSE.txt for license information.
4# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5
6import libear
7from . import call_and_report
8import unittest
9
10import os.path
11import string
12import glob
13
14
15def prepare_cdb(name, target_dir):
16    target_file = "build_{0}.json".format(name)
17    this_dir, _ = os.path.split(__file__)
18    path = os.path.abspath(os.path.join(this_dir, "..", "src"))
19    source_dir = os.path.join(path, "compilation_database")
20    source_file = os.path.join(source_dir, target_file + ".in")
21    target_file = os.path.join(target_dir, "compile_commands.json")
22    with open(source_file, "r") as in_handle:
23        with open(target_file, "w") as out_handle:
24            for line in in_handle:
25                temp = string.Template(line)
26                out_handle.write(temp.substitute(path=path))
27    return target_file
28
29
30def run_analyzer(directory, cdb, args):
31    cmd = ["analyze-build", "--cdb", cdb, "--output", directory] + args
32    return call_and_report(cmd, [])
33
34
35class OutputDirectoryTest(unittest.TestCase):
36    def test_regular_keeps_report_dir(self):
37        with libear.TemporaryDirectory() as tmpdir:
38            cdb = prepare_cdb("regular", tmpdir)
39            exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
40            self.assertTrue(os.path.isdir(reportdir))
41
42    def test_clear_deletes_report_dir(self):
43        with libear.TemporaryDirectory() as tmpdir:
44            cdb = prepare_cdb("clean", tmpdir)
45            exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
46            self.assertFalse(os.path.isdir(reportdir))
47
48    def test_clear_keeps_report_dir_when_asked(self):
49        with libear.TemporaryDirectory() as tmpdir:
50            cdb = prepare_cdb("clean", tmpdir)
51            exit_code, reportdir = run_analyzer(tmpdir, cdb, ["--keep-empty"])
52            self.assertTrue(os.path.isdir(reportdir))
53
54
55class ExitCodeTest(unittest.TestCase):
56    def test_regular_does_not_set_exit_code(self):
57        with libear.TemporaryDirectory() as tmpdir:
58            cdb = prepare_cdb("regular", tmpdir)
59            exit_code, __ = run_analyzer(tmpdir, cdb, [])
60            self.assertFalse(exit_code)
61
62    def test_clear_does_not_set_exit_code(self):
63        with libear.TemporaryDirectory() as tmpdir:
64            cdb = prepare_cdb("clean", tmpdir)
65            exit_code, __ = run_analyzer(tmpdir, cdb, [])
66            self.assertFalse(exit_code)
67
68    def test_regular_sets_exit_code_if_asked(self):
69        with libear.TemporaryDirectory() as tmpdir:
70            cdb = prepare_cdb("regular", tmpdir)
71            exit_code, __ = run_analyzer(tmpdir, cdb, ["--status-bugs"])
72            self.assertTrue(exit_code)
73
74    def test_clear_does_not_set_exit_code_if_asked(self):
75        with libear.TemporaryDirectory() as tmpdir:
76            cdb = prepare_cdb("clean", tmpdir)
77            exit_code, __ = run_analyzer(tmpdir, cdb, ["--status-bugs"])
78            self.assertFalse(exit_code)
79
80    def test_regular_sets_exit_code_if_asked_from_plist(self):
81        with libear.TemporaryDirectory() as tmpdir:
82            cdb = prepare_cdb("regular", tmpdir)
83            exit_code, __ = run_analyzer(tmpdir, cdb, ["--status-bugs", "--plist"])
84            self.assertTrue(exit_code)
85
86    def test_clear_does_not_set_exit_code_if_asked_from_plist(self):
87        with libear.TemporaryDirectory() as tmpdir:
88            cdb = prepare_cdb("clean", tmpdir)
89            exit_code, __ = run_analyzer(tmpdir, cdb, ["--status-bugs", "--plist"])
90            self.assertFalse(exit_code)
91
92
93class OutputFormatTest(unittest.TestCase):
94    @staticmethod
95    def get_html_count(directory):
96        return len(glob.glob(os.path.join(directory, "report-*.html")))
97
98    @staticmethod
99    def get_plist_count(directory):
100        return len(glob.glob(os.path.join(directory, "report-*.plist")))
101
102    @staticmethod
103    def get_sarif_count(directory):
104        return len(glob.glob(os.path.join(directory, "result-*.sarif")))
105
106    def test_default_only_creates_html_report(self):
107        with libear.TemporaryDirectory() as tmpdir:
108            cdb = prepare_cdb("regular", tmpdir)
109            exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
110            self.assertTrue(os.path.exists(os.path.join(reportdir, "index.html")))
111            self.assertEqual(self.get_html_count(reportdir), 2)
112            self.assertEqual(self.get_plist_count(reportdir), 0)
113            self.assertEqual(self.get_sarif_count(reportdir), 0)
114
115    def test_plist_and_html_creates_html_and_plist_reports(self):
116        with libear.TemporaryDirectory() as tmpdir:
117            cdb = prepare_cdb("regular", tmpdir)
118            exit_code, reportdir = run_analyzer(tmpdir, cdb, ["--plist-html"])
119            self.assertTrue(os.path.exists(os.path.join(reportdir, "index.html")))
120            self.assertEqual(self.get_html_count(reportdir), 2)
121            self.assertEqual(self.get_plist_count(reportdir), 5)
122            self.assertEqual(self.get_sarif_count(reportdir), 0)
123
124    def test_plist_only_creates_plist_report(self):
125        with libear.TemporaryDirectory() as tmpdir:
126            cdb = prepare_cdb("regular", tmpdir)
127            exit_code, reportdir = run_analyzer(tmpdir, cdb, ["--plist"])
128            self.assertFalse(os.path.exists(os.path.join(reportdir, "index.html")))
129            self.assertEqual(self.get_html_count(reportdir), 0)
130            self.assertEqual(self.get_plist_count(reportdir), 5)
131            self.assertEqual(self.get_sarif_count(reportdir), 0)
132
133    def test_sarif_only_creates_sarif_result(self):
134        with libear.TemporaryDirectory() as tmpdir:
135            cdb = prepare_cdb("regular", tmpdir)
136            exit_code, reportdir = run_analyzer(tmpdir, cdb, ["--sarif"])
137            self.assertFalse(os.path.exists(os.path.join(reportdir, "index.html")))
138            self.assertTrue(
139                os.path.exists(os.path.join(reportdir, "results-merged.sarif"))
140            )
141            self.assertEqual(self.get_html_count(reportdir), 0)
142            self.assertEqual(self.get_plist_count(reportdir), 0)
143            self.assertEqual(self.get_sarif_count(reportdir), 5)
144
145    def test_sarif_and_html_creates_sarif_and_html_reports(self):
146        with libear.TemporaryDirectory() as tmpdir:
147            cdb = prepare_cdb("regular", tmpdir)
148            exit_code, reportdir = run_analyzer(tmpdir, cdb, ["--sarif-html"])
149            self.assertTrue(os.path.exists(os.path.join(reportdir, "index.html")))
150            self.assertTrue(
151                os.path.exists(os.path.join(reportdir, "results-merged.sarif"))
152            )
153            self.assertEqual(self.get_html_count(reportdir), 2)
154            self.assertEqual(self.get_plist_count(reportdir), 0)
155            self.assertEqual(self.get_sarif_count(reportdir), 5)
156
157
158class FailureReportTest(unittest.TestCase):
159    def test_broken_creates_failure_reports(self):
160        with libear.TemporaryDirectory() as tmpdir:
161            cdb = prepare_cdb("broken", tmpdir)
162            exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
163            self.assertTrue(os.path.isdir(os.path.join(reportdir, "failures")))
164
165    def test_broken_does_not_creates_failure_reports(self):
166        with libear.TemporaryDirectory() as tmpdir:
167            cdb = prepare_cdb("broken", tmpdir)
168            exit_code, reportdir = run_analyzer(tmpdir, cdb, ["--no-failure-reports"])
169            self.assertFalse(os.path.isdir(os.path.join(reportdir, "failures")))
170
171
172class TitleTest(unittest.TestCase):
173    def assertTitleEqual(self, directory, expected):
174        import re
175
176        patterns = [
177            re.compile(r"<title>(?P<page>.*)</title>"),
178            re.compile(r"<h1>(?P<head>.*)</h1>"),
179        ]
180        result = dict()
181
182        index = os.path.join(directory, "index.html")
183        with open(index, "r") as handler:
184            for line in handler.readlines():
185                for regex in patterns:
186                    match = regex.match(line.strip())
187                    if match:
188                        result.update(match.groupdict())
189                        break
190        self.assertEqual(result["page"], result["head"])
191        self.assertEqual(result["page"], expected)
192
193    def test_default_title_in_report(self):
194        with libear.TemporaryDirectory() as tmpdir:
195            cdb = prepare_cdb("broken", tmpdir)
196            exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
197            self.assertTitleEqual(reportdir, "src - analyzer results")
198
199    def test_given_title_in_report(self):
200        with libear.TemporaryDirectory() as tmpdir:
201            cdb = prepare_cdb("broken", tmpdir)
202            exit_code, reportdir = run_analyzer(
203                tmpdir, cdb, ["--html-title", "this is the title"]
204            )
205            self.assertTitleEqual(reportdir, "this is the title")
206