1# -*- coding: utf-8 -*-
2#                     The LLVM Compiler Infrastructure
3#
4# This file is distributed under the University of Illinois Open Source
5# License. See LICENSE.TXT for details.
6
7import libear
8from . import call_and_report
9import unittest
10
11import os.path
12import string
13import glob
14
15
16def prepare_cdb(name, target_dir):
17    target_file = 'build_{0}.json'.format(name)
18    this_dir, _ = os.path.split(__file__)
19    path = os.path.normpath(os.path.join(this_dir, '..', 'src'))
20    source_dir = os.path.join(path, 'compilation_database')
21    source_file = os.path.join(source_dir, target_file + '.in')
22    target_file = os.path.join(target_dir, 'compile_commands.json')
23    with open(source_file, 'r') as in_handle:
24        with open(target_file, 'w') as out_handle:
25            for line in in_handle:
26                temp = string.Template(line)
27                out_handle.write(temp.substitute(path=path))
28    return target_file
29
30
31def run_analyzer(directory, cdb, args):
32    cmd = ['analyze-build', '--cdb', cdb, '--output', directory] \
33        + args
34    return call_and_report(cmd, [])
35
36
37class OutputDirectoryTest(unittest.TestCase):
38    def test_regular_keeps_report_dir(self):
39        with libear.TemporaryDirectory() as tmpdir:
40            cdb = prepare_cdb('regular', tmpdir)
41            exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
42            self.assertTrue(os.path.isdir(reportdir))
43
44    def test_clear_deletes_report_dir(self):
45        with libear.TemporaryDirectory() as tmpdir:
46            cdb = prepare_cdb('clean', tmpdir)
47            exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
48            self.assertFalse(os.path.isdir(reportdir))
49
50    def test_clear_keeps_report_dir_when_asked(self):
51        with libear.TemporaryDirectory() as tmpdir:
52            cdb = prepare_cdb('clean', tmpdir)
53            exit_code, reportdir = run_analyzer(tmpdir, cdb, ['--keep-empty'])
54            self.assertTrue(os.path.isdir(reportdir))
55
56
57class ExitCodeTest(unittest.TestCase):
58    def test_regular_does_not_set_exit_code(self):
59        with libear.TemporaryDirectory() as tmpdir:
60            cdb = prepare_cdb('regular', tmpdir)
61            exit_code, __ = run_analyzer(tmpdir, cdb, [])
62            self.assertFalse(exit_code)
63
64    def test_clear_does_not_set_exit_code(self):
65        with libear.TemporaryDirectory() as tmpdir:
66            cdb = prepare_cdb('clean', tmpdir)
67            exit_code, __ = run_analyzer(tmpdir, cdb, [])
68            self.assertFalse(exit_code)
69
70    def test_regular_sets_exit_code_if_asked(self):
71        with libear.TemporaryDirectory() as tmpdir:
72            cdb = prepare_cdb('regular', tmpdir)
73            exit_code, __ = run_analyzer(tmpdir, cdb, ['--status-bugs'])
74            self.assertTrue(exit_code)
75
76    def test_clear_does_not_set_exit_code_if_asked(self):
77        with libear.TemporaryDirectory() as tmpdir:
78            cdb = prepare_cdb('clean', tmpdir)
79            exit_code, __ = run_analyzer(tmpdir, cdb, ['--status-bugs'])
80            self.assertFalse(exit_code)
81
82    def test_regular_sets_exit_code_if_asked_from_plist(self):
83        with libear.TemporaryDirectory() as tmpdir:
84            cdb = prepare_cdb('regular', tmpdir)
85            exit_code, __ = run_analyzer(
86                tmpdir, cdb, ['--status-bugs', '--plist'])
87            self.assertTrue(exit_code)
88
89    def test_clear_does_not_set_exit_code_if_asked_from_plist(self):
90        with libear.TemporaryDirectory() as tmpdir:
91            cdb = prepare_cdb('clean', tmpdir)
92            exit_code, __ = run_analyzer(
93                tmpdir, cdb, ['--status-bugs', '--plist'])
94            self.assertFalse(exit_code)
95
96
97class OutputFormatTest(unittest.TestCase):
98    @staticmethod
99    def get_html_count(directory):
100        return len(glob.glob(os.path.join(directory, 'report-*.html')))
101
102    @staticmethod
103    def get_plist_count(directory):
104        return len(glob.glob(os.path.join(directory, 'report-*.plist')))
105
106    def test_default_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(
111                os.path.exists(os.path.join(reportdir, 'index.html')))
112            self.assertEqual(self.get_html_count(reportdir), 2)
113            self.assertEqual(self.get_plist_count(reportdir), 0)
114
115    def test_plist_and_html_creates_html_report(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(
120                os.path.exists(os.path.join(reportdir, 'index.html')))
121            self.assertEqual(self.get_html_count(reportdir), 2)
122            self.assertEqual(self.get_plist_count(reportdir), 5)
123
124    def test_plist_does_not_creates_html_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(
129                os.path.exists(os.path.join(reportdir, 'index.html')))
130            self.assertEqual(self.get_html_count(reportdir), 0)
131            self.assertEqual(self.get_plist_count(reportdir), 5)
132
133
134class FailureReportTest(unittest.TestCase):
135    def test_broken_creates_failure_reports(self):
136        with libear.TemporaryDirectory() as tmpdir:
137            cdb = prepare_cdb('broken', tmpdir)
138            exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
139            self.assertTrue(
140                os.path.isdir(os.path.join(reportdir, 'failures')))
141
142    def test_broken_does_not_creates_failure_reports(self):
143        with libear.TemporaryDirectory() as tmpdir:
144            cdb = prepare_cdb('broken', tmpdir)
145            exit_code, reportdir = run_analyzer(
146                tmpdir, cdb, ['--no-failure-reports'])
147            self.assertFalse(
148                os.path.isdir(os.path.join(reportdir, 'failures')))
149
150
151class TitleTest(unittest.TestCase):
152    def assertTitleEqual(self, directory, expected):
153        import re
154        patterns = [
155            re.compile(r'<title>(?P<page>.*)</title>'),
156            re.compile(r'<h1>(?P<head>.*)</h1>')
157        ]
158        result = dict()
159
160        index = os.path.join(directory, 'index.html')
161        with open(index, 'r') as handler:
162            for line in handler.readlines():
163                for regex in patterns:
164                    match = regex.match(line.strip())
165                    if match:
166                        result.update(match.groupdict())
167                        break
168        self.assertEqual(result['page'], result['head'])
169        self.assertEqual(result['page'], expected)
170
171    def test_default_title_in_report(self):
172        with libear.TemporaryDirectory() as tmpdir:
173            cdb = prepare_cdb('broken', tmpdir)
174            exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
175            self.assertTitleEqual(reportdir, 'src - analyzer results')
176
177    def test_given_title_in_report(self):
178        with libear.TemporaryDirectory() as tmpdir:
179            cdb = prepare_cdb('broken', tmpdir)
180            exit_code, reportdir = run_analyzer(
181                tmpdir, cdb, ['--html-title', 'this is the title'])
182            self.assertTitleEqual(reportdir, 'this is the title')
183