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 make_args, silent_check_call, silent_call, create_empty_file
8import unittest
9
10import os.path
11import json
12
13
14class CompilationDatabaseTest(unittest.TestCase):
15    @staticmethod
16    def run_intercept(tmpdir, args):
17        result = os.path.join(tmpdir, 'cdb.json')
18        make = make_args(tmpdir) + args
19        silent_check_call(
20            ['intercept-build', '--cdb', result] + make)
21        return result
22
23    @staticmethod
24    def count_entries(filename):
25        with open(filename, 'r') as handler:
26            content = json.load(handler)
27            return len(content)
28
29    def test_successful_build(self):
30        with libear.TemporaryDirectory() as tmpdir:
31            result = self.run_intercept(tmpdir, ['build_regular'])
32            self.assertTrue(os.path.isfile(result))
33            self.assertEqual(5, self.count_entries(result))
34
35    def test_successful_build_with_wrapper(self):
36        with libear.TemporaryDirectory() as tmpdir:
37            result = os.path.join(tmpdir, 'cdb.json')
38            make = make_args(tmpdir) + ['build_regular']
39            silent_check_call(['intercept-build', '--cdb', result,
40                               '--override-compiler'] + make)
41            self.assertTrue(os.path.isfile(result))
42            self.assertEqual(5, self.count_entries(result))
43
44    @unittest.skipIf(os.getenv('TRAVIS'), 'ubuntu make return -11')
45    def test_successful_build_parallel(self):
46        with libear.TemporaryDirectory() as tmpdir:
47            result = self.run_intercept(tmpdir, ['-j', '4', 'build_regular'])
48            self.assertTrue(os.path.isfile(result))
49            self.assertEqual(5, self.count_entries(result))
50
51    @unittest.skipIf(os.getenv('TRAVIS'), 'ubuntu env remove clang from path')
52    def test_successful_build_on_empty_env(self):
53        with libear.TemporaryDirectory() as tmpdir:
54            result = os.path.join(tmpdir, 'cdb.json')
55            make = make_args(tmpdir) + ['CC=clang', 'build_regular']
56            silent_check_call(['intercept-build', '--cdb', result,
57                               'env', '-'] + make)
58            self.assertTrue(os.path.isfile(result))
59            self.assertEqual(5, self.count_entries(result))
60
61    def test_successful_build_all_in_one(self):
62        with libear.TemporaryDirectory() as tmpdir:
63            result = self.run_intercept(tmpdir, ['build_all_in_one'])
64            self.assertTrue(os.path.isfile(result))
65            self.assertEqual(5, self.count_entries(result))
66
67    def test_not_successful_build(self):
68        with libear.TemporaryDirectory() as tmpdir:
69            result = os.path.join(tmpdir, 'cdb.json')
70            make = make_args(tmpdir) + ['build_broken']
71            silent_call(
72                ['intercept-build', '--cdb', result] + make)
73            self.assertTrue(os.path.isfile(result))
74            self.assertEqual(2, self.count_entries(result))
75
76
77class ExitCodeTest(unittest.TestCase):
78    @staticmethod
79    def run_intercept(tmpdir, target):
80        result = os.path.join(tmpdir, 'cdb.json')
81        make = make_args(tmpdir) + [target]
82        return silent_call(
83            ['intercept-build', '--cdb', result] + make)
84
85    def test_successful_build(self):
86        with libear.TemporaryDirectory() as tmpdir:
87            exitcode = self.run_intercept(tmpdir, 'build_clean')
88            self.assertFalse(exitcode)
89
90    def test_not_successful_build(self):
91        with libear.TemporaryDirectory() as tmpdir:
92            exitcode = self.run_intercept(tmpdir, 'build_broken')
93            self.assertTrue(exitcode)
94
95
96class ResumeFeatureTest(unittest.TestCase):
97    @staticmethod
98    def run_intercept(tmpdir, target, args):
99        result = os.path.join(tmpdir, 'cdb.json')
100        make = make_args(tmpdir) + [target]
101        silent_check_call(
102            ['intercept-build', '--cdb', result] + args + make)
103        return result
104
105    @staticmethod
106    def count_entries(filename):
107        with open(filename, 'r') as handler:
108            content = json.load(handler)
109            return len(content)
110
111    def test_overwrite_existing_cdb(self):
112        with libear.TemporaryDirectory() as tmpdir:
113            result = self.run_intercept(tmpdir, 'build_clean', [])
114            self.assertTrue(os.path.isfile(result))
115            result = self.run_intercept(tmpdir, 'build_regular', [])
116            self.assertTrue(os.path.isfile(result))
117            self.assertEqual(2, self.count_entries(result))
118
119    def test_append_to_existing_cdb(self):
120        with libear.TemporaryDirectory() as tmpdir:
121            result = self.run_intercept(tmpdir, 'build_clean', [])
122            self.assertTrue(os.path.isfile(result))
123            result = self.run_intercept(tmpdir, 'build_regular', ['--append'])
124            self.assertTrue(os.path.isfile(result))
125            self.assertEqual(5, self.count_entries(result))
126
127
128class ResultFormatingTest(unittest.TestCase):
129    @staticmethod
130    def run_intercept(tmpdir, command):
131        result = os.path.join(tmpdir, 'cdb.json')
132        silent_check_call(
133            ['intercept-build', '--cdb', result] + command,
134            cwd=tmpdir)
135        with open(result, 'r') as handler:
136            content = json.load(handler)
137            return content
138
139    def assert_creates_number_of_entries(self, command, count):
140        with libear.TemporaryDirectory() as tmpdir:
141            filename = os.path.join(tmpdir, 'test.c')
142            create_empty_file(filename)
143            command.append(filename)
144            cmd = ['sh', '-c', ' '.join(command)]
145            cdb = self.run_intercept(tmpdir, cmd)
146            self.assertEqual(count, len(cdb))
147
148    def test_filter_preprocessor_only_calls(self):
149        self.assert_creates_number_of_entries(['cc', '-c'], 1)
150        self.assert_creates_number_of_entries(['cc', '-c', '-E'], 0)
151        self.assert_creates_number_of_entries(['cc', '-c', '-M'], 0)
152        self.assert_creates_number_of_entries(['cc', '-c', '-MM'], 0)
153
154    def assert_command_creates_entry(self, command, expected):
155        with libear.TemporaryDirectory() as tmpdir:
156            filename = os.path.join(tmpdir, command[-1])
157            create_empty_file(filename)
158            cmd = ['sh', '-c', ' '.join(command)]
159            cdb = self.run_intercept(tmpdir, cmd)
160            self.assertEqual(' '.join(expected), cdb[0]['command'])
161
162    def test_filter_preprocessor_flags(self):
163        self.assert_command_creates_entry(
164            ['cc', '-c', '-MD', 'test.c'],
165            ['cc', '-c', 'test.c'])
166        self.assert_command_creates_entry(
167            ['cc', '-c', '-MMD', 'test.c'],
168            ['cc', '-c', 'test.c'])
169        self.assert_command_creates_entry(
170            ['cc', '-c', '-MD', '-MF', 'test.d', 'test.c'],
171            ['cc', '-c', 'test.c'])
172
173    def test_pass_language_flag(self):
174        self.assert_command_creates_entry(
175            ['cc', '-c', '-x', 'c', 'test.c'],
176            ['cc', '-c', '-x', 'c', 'test.c'])
177        self.assert_command_creates_entry(
178            ['cc', '-c', 'test.c'],
179            ['cc', '-c', 'test.c'])
180
181    def test_pass_arch_flags(self):
182        self.assert_command_creates_entry(
183            ['clang', '-c', 'test.c'],
184            ['cc', '-c', 'test.c'])
185        self.assert_command_creates_entry(
186            ['clang', '-c', '-arch', 'i386', 'test.c'],
187            ['cc', '-c', '-arch', 'i386', 'test.c'])
188        self.assert_command_creates_entry(
189            ['clang', '-c', '-arch', 'i386', '-arch', 'armv7l', 'test.c'],
190            ['cc', '-c', '-arch', 'i386', '-arch', 'armv7l', 'test.c'])
191