3 # Copyright 2015 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
7 """Tests for chromium.ycm_extra_conf.
9 These tests should be getting picked up by the PRESUBMIT.py in /tools/vim.
10 Currently the tests only run on Linux and require 'ninja' to be available on
11 PATH. Due to these requirements, the tests should only be run on upload.
27 make_executable
= False):
30 If a file already exists at |path|, it will be overwritten.
33 path: (String) Absolute path for file to be created.
34 copy_from: (String or None) Absolute path to source file. If valid, the
35 contents of this file will be written to |path|.
36 format_with: (Dictionary or None) Only valid if |copy_from| is also valid.
37 The contents of the file at |copy_from| will be passed through
38 string.Formatter.vformat() with this parameter as the dictionary.
39 make_executable: (Boolean) If true, |file| will be made executable.
41 if not os
.path
.isabs(path
):
43 'Argument |path| needs to be an absolute path. Got: "{}"'.format(path
))
44 with
open(path
, 'w') as f
:
46 with
open(copy_from
, 'r') as source
:
47 contents
= source
.read()
49 formatter
= string
.Formatter()
50 contents
= formatter
.vformat(contents
, None, format_with
)
53 statinfo
= os
.stat(path
)
54 os
.chmod(path
, statinfo
.st_mode | stat
.S_IXUSR
)
56 @unittest.skipIf(sys
.platform
.startswith('linux'),
57 'Tests are only valid on Linux.')
58 class Chromium_ycmExtraConfTest_NotOnLinux(unittest
.TestCase
):
59 def testAlwaysFailsIfNotRunningOnLinux(self
):
60 self
.fail('Changes to chromium.ycm_extra_conf.py currently need to be ' \
61 'uploaded from Linux since the tests only run on Linux.')
63 @unittest.skipUnless(sys
.platform
.startswith('linux'),
64 'Tests are only valid on Linux.')
65 class Chromium_ycmExtraConfTest(unittest
.TestCase
):
67 def SetUpFakeChromeTreeBelowPath(self
):
68 """Create fake Chromium source tree under self.test_root.
70 The fake source tree has the following contents:
86 self
.chrome_root
= os
.path
.abspath(os
.path
.normpath(
87 os
.path
.join(self
.test_root
, 'src')))
88 self
.out_dir
= os
.path
.join(self
.chrome_root
, 'out', 'Debug')
90 os
.makedirs(self
.chrome_root
)
91 os
.makedirs(os
.path
.join(self
.chrome_root
, '.git'))
92 os
.makedirs(self
.out_dir
)
94 CreateFile(os
.path
.join(self
.test_root
, '.gclient'))
95 CreateFile(os
.path
.join(self
.chrome_root
, 'DEPS'))
96 CreateFile(os
.path
.join(self
.chrome_root
, 'three.cc'))
98 # Fake ninja build file. Applications of 'cxx' rule are tagged by which
99 # source file was used as input so that the test can verify that the correct
100 # build dependency was used.
101 CreateFile(os
.path
.join(self
.out_dir
, 'build.ninja'),
102 copy_from
=os
.path
.join(self
.test_data_path
,
103 'fake_build_ninja.txt'))
105 def NormalizeString(self
, string
):
106 return string
.replace(self
.out_dir
, '[OUT]').\
107 replace(self
.chrome_root
, '[SRC]')
109 def NormalizeStringsInList(self
, list_of_strings
):
110 return [self
.NormalizeString(s
) for s
in list_of_strings
]
113 self
.actual_chrome_root
= os
.path
.normpath(
114 os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), '../../..'))
115 sys
.path
.append(os
.path
.join(self
.actual_chrome_root
, 'tools', 'vim'))
116 self
.test_data_path
= os
.path
.join(self
.actual_chrome_root
, 'tools', 'vim',
118 self
.ycm_extra_conf
= imp
.load_source('ycm_extra_conf',
119 'chromium.ycm_extra_conf.py')
120 self
.test_root
= tempfile
.mkdtemp()
121 self
.SetUpFakeChromeTreeBelowPath()
125 shutil
.rmtree(self
.test_root
)
127 def testNinjaIsAvailable(self
):
128 p
= subprocess
.Popen(['ninja', '--version'], stdout
=subprocess
.PIPE
)
129 _
, _
= p
.communicate()
130 self
.assertFalse(p
.returncode
)
132 def testFindChromeSrc(self
):
133 chrome_source
= self
.ycm_extra_conf
.FindChromeSrcFromFilename(
134 os
.path
.join(self
.chrome_root
, 'chrome', 'one.cpp'))
135 self
.assertEquals(chrome_source
, self
.chrome_root
)
137 chrome_source
= self
.ycm_extra_conf
.FindChromeSrcFromFilename(
138 os
.path
.join(self
.chrome_root
, 'one.cpp'))
139 self
.assertEquals(chrome_source
, self
.chrome_root
)
141 def testCommandLineForKnownCppFile(self
):
142 command_line
= self
.ycm_extra_conf
.GetClangCommandLineFromNinjaForSource(
143 self
.out_dir
, os
.path
.join(self
.chrome_root
, 'one.cpp'))
145 command_line
, ('../../fake-clang++ -Ia -isysroot /mac.sdk -Itag-one '
146 '../../one.cpp -o obj/one.o'))
148 def testCommandLineForUnknownCppFile(self
):
149 command_line
= self
.ycm_extra_conf
.GetClangCommandLineFromNinjaForSource(
150 self
.out_dir
, os
.path
.join(self
.chrome_root
, 'unknown.cpp'))
151 self
.assertEquals(command_line
, None)
153 def testGetClangOptionsForKnownCppFile(self
):
155 self
.ycm_extra_conf
.GetClangOptionsFromNinjaForFilename(
156 self
.chrome_root
, os
.path
.join(self
.chrome_root
, 'one.cpp'))
157 self
.assertEquals(self
.NormalizeStringsInList(clang_options
), [
159 '-Wno-unknown-warning-option',
166 def testGetFlagsForFileForKnownCppFile(self
):
167 result
= self
.ycm_extra_conf
.FlagsForFile(
168 os
.path
.join(self
.chrome_root
, 'one.cpp'))
169 self
.assertTrue(result
)
170 self
.assertTrue('do_cache' in result
)
171 self
.assertTrue(result
['do_cache'])
172 self
.assertTrue('flags' in result
)
173 self
.assertEquals(self
.NormalizeStringsInList(result
['flags']), [
174 '-DUSE_CLANG_COMPLETER',
178 '-Wno-unknown-warning-option',
185 def testGetFlagsForFileForUnknownCppFile(self
):
186 result
= self
.ycm_extra_conf
.FlagsForFile(
187 os
.path
.join(self
.chrome_root
, 'nonexistent.cpp'))
188 self
.assertTrue(result
)
189 self
.assertTrue('do_cache' in result
)
190 self
.assertTrue(result
['do_cache'])
191 self
.assertTrue('flags' in result
)
192 self
.assertEquals(self
.NormalizeStringsInList(result
['flags']), [
193 '-DUSE_CLANG_COMPLETER',
197 '-Wno-unknown-warning-option',
201 '-I[OUT]/tag-default'
204 def testGetFlagsForFileForUnknownHeaderFile(self
):
205 result
= self
.ycm_extra_conf
.FlagsForFile(
206 os
.path
.join(self
.chrome_root
, 'nonexistent.h'))
207 self
.assertTrue(result
)
208 self
.assertTrue('do_cache' in result
)
209 self
.assertTrue(result
['do_cache'])
210 self
.assertTrue('flags' in result
)
211 self
.assertEquals(self
.NormalizeStringsInList(result
['flags']), [
212 '-DUSE_CLANG_COMPLETER',
216 '-Wno-unknown-warning-option',
220 '-I[OUT]/tag-default'
223 def testGetFlagsForFileForKnownHeaderFileWithAssociatedCppFile(self
):
224 result
= self
.ycm_extra_conf
.FlagsForFile(
225 os
.path
.join(self
.chrome_root
, 'three.h'))
226 self
.assertTrue(result
)
227 self
.assertTrue('do_cache' in result
)
228 self
.assertTrue(result
['do_cache'])
229 self
.assertTrue('flags' in result
)
230 self
.assertEquals(self
.NormalizeStringsInList(result
['flags']), [
231 '-DUSE_CLANG_COMPLETER',
235 '-Wno-unknown-warning-option',
242 def testSourceFileWithNonClangOutputs(self
):
243 # Verify assumption that four.cc has non-compiler-output listed as the first
245 p
= subprocess
.Popen(['ninja', '-C', self
.out_dir
, '-t',
246 'query', '../../four.cc'],
247 stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
248 stdout
, _
= p
.communicate()
249 self
.assertFalse(p
.returncode
)
250 self
.assertEquals(stdout
,
253 ' obj/linker-output.o\n'
256 result
= self
.ycm_extra_conf
.FlagsForFile(
257 os
.path
.join(self
.chrome_root
, 'four.cc'))
258 self
.assertTrue(result
)
259 self
.assertTrue('do_cache' in result
)
260 self
.assertTrue(result
['do_cache'])
261 self
.assertTrue('flags' in result
)
262 self
.assertEquals(self
.NormalizeStringsInList(result
['flags']), [
263 '-DUSE_CLANG_COMPLETER',
267 '-Wno-unknown-warning-option',
274 def testSourceFileWithOnlyNonClangOutputs(self
):
275 result
= self
.ycm_extra_conf
.FlagsForFile(
276 os
.path
.join(self
.chrome_root
, 'five.cc'))
277 self
.assertTrue(result
)
278 self
.assertTrue('do_cache' in result
)
279 self
.assertTrue(result
['do_cache'])
280 self
.assertTrue('flags' in result
)
281 self
.assertEquals(self
.NormalizeStringsInList(result
['flags']), [
282 '-DUSE_CLANG_COMPLETER',
286 '-Wno-unknown-warning-option',
290 '-I[OUT]/tag-default'
293 if __name__
== '__main__':