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
8import libscanbuild.report as sut
9import unittest
10import os
11import os.path
12
13
14def run_bug_parse(content):
15    with libear.TemporaryDirectory() as tmpdir:
16        file_name = os.path.join(tmpdir, 'test.html')
17        with open(file_name, 'w') as handle:
18            handle.writelines(content)
19        for bug in sut.parse_bug_html(file_name):
20            return bug
21
22
23def run_crash_parse(content, preproc):
24    with libear.TemporaryDirectory() as tmpdir:
25        file_name = os.path.join(tmpdir, preproc + '.info.txt')
26        with open(file_name, 'w') as handle:
27            handle.writelines(content)
28        return sut.parse_crash(file_name)
29
30
31class ParseFileTest(unittest.TestCase):
32
33    def test_parse_bug(self):
34        content = [
35            "some header\n",
36            "<!-- BUGDESC Division by zero -->\n",
37            "<!-- BUGTYPE Division by zero -->\n",
38            "<!-- BUGCATEGORY Logic error -->\n",
39            "<!-- BUGFILE xx -->\n",
40            "<!-- BUGLINE 5 -->\n",
41            "<!-- BUGCOLUMN 22 -->\n",
42            "<!-- BUGPATHLENGTH 4 -->\n",
43            "<!-- BUGMETAEND -->\n",
44            "<!-- REPORTHEADER -->\n",
45            "some tails\n"]
46        result = run_bug_parse(content)
47        self.assertEqual(result['bug_category'], 'Logic error')
48        self.assertEqual(result['bug_path_length'], 4)
49        self.assertEqual(result['bug_line'], 5)
50        self.assertEqual(result['bug_description'], 'Division by zero')
51        self.assertEqual(result['bug_type'], 'Division by zero')
52        self.assertEqual(result['bug_file'], 'xx')
53
54    def test_parse_bug_empty(self):
55        content = []
56        result = run_bug_parse(content)
57        self.assertEqual(result['bug_category'], 'Other')
58        self.assertEqual(result['bug_path_length'], 1)
59        self.assertEqual(result['bug_line'], 0)
60
61    def test_parse_crash(self):
62        content = [
63            "/some/path/file.c\n",
64            "Some very serious Error\n",
65            "bla\n",
66            "bla-bla\n"]
67        result = run_crash_parse(content, 'file.i')
68        self.assertEqual(result['source'], content[0].rstrip())
69        self.assertEqual(result['problem'], content[1].rstrip())
70        self.assertEqual(os.path.basename(result['file']),
71                         'file.i')
72        self.assertEqual(os.path.basename(result['info']),
73                         'file.i.info.txt')
74        self.assertEqual(os.path.basename(result['stderr']),
75                         'file.i.stderr.txt')
76
77    def test_parse_real_crash(self):
78        import libscanbuild.runner as sut2
79        import re
80        with libear.TemporaryDirectory() as tmpdir:
81            filename = os.path.join(tmpdir, 'test.c')
82            with open(filename, 'w') as handle:
83                handle.write('int main() { return 0')
84            # produce failure report
85            opts = {
86                'clang': 'clang',
87                'directory': os.getcwd(),
88                'flags': [],
89                'file': filename,
90                'output_dir': tmpdir,
91                'language': 'c',
92                'error_type': 'other_error',
93                'error_output': 'some output',
94                'exit_code': 13
95            }
96            sut2.report_failure(opts)
97            # find the info file
98            pp_file = None
99            for root, _, files in os.walk(tmpdir):
100                keys = [os.path.join(root, name) for name in files]
101                for key in keys:
102                    if re.match(r'^(.*/)+clang(.*)\.i$', key):
103                        pp_file = key
104            self.assertIsNot(pp_file, None)
105            # read the failure report back
106            result = sut.parse_crash(pp_file + '.info.txt')
107            self.assertEqual(result['source'], filename)
108            self.assertEqual(result['problem'], 'Other Error')
109            self.assertEqual(result['file'], pp_file)
110            self.assertEqual(result['info'], pp_file + '.info.txt')
111            self.assertEqual(result['stderr'], pp_file + '.stderr.txt')
112
113
114class ReportMethodTest(unittest.TestCase):
115
116    def test_chop(self):
117        self.assertEqual('file', sut.chop('/prefix', '/prefix/file'))
118        self.assertEqual('file', sut.chop('/prefix/', '/prefix/file'))
119        self.assertEqual('lib/file', sut.chop('/prefix/', '/prefix/lib/file'))
120        self.assertEqual('/prefix/file', sut.chop('', '/prefix/file'))
121
122    def test_chop_when_cwd(self):
123        self.assertEqual('../src/file', sut.chop('/cwd', '/src/file'))
124        self.assertEqual('../src/file', sut.chop('/prefix/cwd',
125                                                 '/prefix/src/file'))
126
127
128class GetPrefixFromCompilationDatabaseTest(unittest.TestCase):
129
130    def test_with_different_filenames(self):
131        self.assertEqual(
132            sut.commonprefix(['/tmp/a.c', '/tmp/b.c']), '/tmp')
133
134    def test_with_different_dirnames(self):
135        self.assertEqual(
136            sut.commonprefix(['/tmp/abs/a.c', '/tmp/ack/b.c']), '/tmp')
137
138    def test_no_common_prefix(self):
139        self.assertEqual(
140            sut.commonprefix(['/tmp/abs/a.c', '/usr/ack/b.c']), '/')
141
142    def test_with_single_file(self):
143        self.assertEqual(
144            sut.commonprefix(['/tmp/a.c']), '/tmp')
145
146    def test_empty(self):
147        self.assertEqual(
148            sut.commonprefix([]), '')
149