1#!/usr/bin/env python
2# Copyright (c) 2014 Google Inc. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Tests for analyzer
7"""
8
9import json
10import TestGyp
11
12found = 'Found dependency'
13found_all = 'Found dependency (all)'
14not_found = 'No dependencies'
15
16
17def _CreateConfigFile(files, targets):
18  """Creates the analyzer conflig file, which is used as the input to analyzer.
19  See description of analyzer.py for description of the arguments."""
20  f = open('test_file', 'w')
21  to_write = {'files': files, 'targets': targets }
22  json.dump(to_write, f)
23  f.close()
24
25
26def _CreateBogusConfigFile():
27  f = open('test_file','w')
28  f.write('bogus')
29  f.close()
30
31
32def _ReadOutputFileContents():
33  f = open('analyzer_output', 'r')
34  result = json.load(f)
35  f.close()
36  return result
37
38
39# NOTE: this would be clearer if it subclassed TestGypCustom, but that trips
40# over a bug in pylint (E1002).
41test = TestGyp.TestGypCustom(format='analyzer')
42
43def CommonArgs():
44  return ('-Gconfig_path=test_file',
45           '-Ganalyzer_output_path=analyzer_output')
46
47
48def run_analyzer(*args, **kw):
49  """Runs the test specifying a particular config and output path."""
50  args += CommonArgs()
51  test.run_gyp('test.gyp', *args, **kw)
52
53
54def run_analyzer2(*args, **kw):
55  """Same as run_analyzer(), but passes in test2.gyp instead of test.gyp."""
56  args += CommonArgs()
57  test.run_gyp('test2.gyp', *args, **kw)
58
59
60def run_analyzer3(*args, **kw):
61  """Same as run_analyzer(), but passes in test3.gyp instead of test.gyp."""
62  args += CommonArgs()
63  test.run_gyp('test3.gyp', *args, **kw)
64
65
66def run_analyzer4(*args, **kw):
67  """Same as run_analyzer(), but passes in test3.gyp instead of test.gyp."""
68  args += CommonArgs()
69  test.run_gyp('test4.gyp', *args, **kw)
70
71
72def EnsureContains(targets=set(), matched=False, build_targets=set()):
73  """Verifies output contains |targets|."""
74  result = _ReadOutputFileContents()
75  if result.get('error', None):
76    print 'unexpected error', result.get('error')
77    test.fail_test()
78
79  if result.get('warning', None):
80    print 'unexpected warning', result.get('warning')
81    test.fail_test()
82
83  actual_targets = set(result['targets'])
84  if actual_targets != targets:
85    print 'actual targets:', actual_targets, '\nexpected targets:', targets
86    test.fail_test()
87
88  actual_build_targets = set(result['build_targets'])
89  if actual_build_targets != build_targets:
90    print 'actual build_targets:', actual_build_targets, \
91           '\nexpected build_targets:', build_targets
92    test.fail_test()
93
94  if matched and result['status'] != found:
95    print 'expected', found, 'got', result['status']
96    test.fail_test()
97  elif not matched and result['status'] != not_found:
98    print 'expected', not_found, 'got', result['status']
99    test.fail_test()
100
101
102def EnsureMatchedAll(targets):
103  result = _ReadOutputFileContents()
104  if result.get('error', None):
105    print 'unexpected error', result.get('error')
106    test.fail_test()
107
108  if result.get('warning', None):
109    print 'unexpected warning', result.get('warning')
110    test.fail_test()
111
112  if result['status'] != found_all:
113    print 'expected', found_all, 'got', result['status']
114    test.fail_test()
115
116  actual_targets = set(result['targets'])
117  if actual_targets != targets:
118    print 'actual targets:', actual_targets, '\nexpected targets:', targets
119    test.fail_test()
120
121
122def EnsureError(expected_error_string):
123  """Verifies output contains the error string."""
124  result = _ReadOutputFileContents()
125  if result.get('error', '').find(expected_error_string) == -1:
126    print 'actual error:', result.get('error', ''), '\nexpected error:', \
127        expected_error_string
128    test.fail_test()
129
130
131def EnsureStdoutContains(expected_error_string):
132  if test.stdout().find(expected_error_string) == -1:
133    print 'actual stdout:', test.stdout(), '\nexpected stdout:', \
134        expected_error_string
135    test.fail_test()
136
137
138def EnsureWarning(expected_warning_string):
139  """Verifies output contains the warning string."""
140  result = _ReadOutputFileContents()
141  if result.get('warning', '').find(expected_warning_string) == -1:
142    print 'actual warning:', result.get('warning', ''), \
143        '\nexpected warning:', expected_warning_string
144    test.fail_test()
145
146# Verifies config_path must be specified.
147test.run_gyp('test.gyp')
148EnsureStdoutContains('Must specify files to analyze via config_path')
149
150# Verifies config_path must point to a valid file.
151test.run_gyp('test.gyp', '-Gconfig_path=bogus_file',
152             '-Ganalyzer_output_path=analyzer_output')
153EnsureError('Unable to open file bogus_file')
154
155# Verify get warning when bad target is specified.
156_CreateConfigFile(['exe2.c'], ['bad_target'])
157run_analyzer()
158EnsureWarning('Unable to find all targets')
159
160# Verifies config_path must point to a valid json file.
161_CreateBogusConfigFile()
162run_analyzer()
163EnsureError('Unable to parse config file test_file')
164
165# Trivial test of a source.
166_CreateConfigFile(['foo.c'], [])
167run_analyzer()
168EnsureContains(matched=True, build_targets={'exe'})
169
170# Conditional source that is excluded.
171_CreateConfigFile(['conditional_source.c'], [])
172run_analyzer()
173EnsureContains(matched=False)
174
175# Conditional source that is included by way of argument.
176_CreateConfigFile(['conditional_source.c'], [])
177run_analyzer('-Dtest_variable=1')
178EnsureContains(matched=True, build_targets={'exe'})
179
180# Two unknown files.
181_CreateConfigFile(['unknown1.c', 'unoknow2.cc'], [])
182run_analyzer()
183EnsureContains()
184
185# Two unknown files.
186_CreateConfigFile(['unknown1.c', 'subdir/subdir_sourcex.c'], [])
187run_analyzer()
188EnsureContains()
189
190# Included dependency
191_CreateConfigFile(['unknown1.c', 'subdir/subdir_source.c'], [])
192run_analyzer()
193EnsureContains(matched=True, build_targets={'exe', 'exe3'})
194
195# Included inputs to actions.
196_CreateConfigFile(['action_input.c'], [])
197run_analyzer()
198EnsureContains(matched=True, build_targets={'exe'})
199
200# Don't consider outputs.
201_CreateConfigFile(['action_output.c'], [])
202run_analyzer()
203EnsureContains(matched=False)
204
205# Rule inputs.
206_CreateConfigFile(['rule_input.c'], [])
207run_analyzer()
208EnsureContains(matched=True, build_targets={'exe'})
209
210# Ignore path specified with PRODUCT_DIR.
211_CreateConfigFile(['product_dir_input.c'], [])
212run_analyzer()
213EnsureContains(matched=False)
214
215# Path specified via a variable.
216_CreateConfigFile(['subdir/subdir_source2.c'], [])
217run_analyzer()
218EnsureContains(matched=True, build_targets={'exe'})
219
220# Verifies paths with // are fixed up correctly.
221_CreateConfigFile(['parent_source.c'], [])
222run_analyzer()
223EnsureContains(matched=True, build_targets={'exe', 'exe3'})
224
225# Verifies relative paths are resolved correctly.
226_CreateConfigFile(['subdir/subdir_source.h'], [])
227run_analyzer()
228EnsureContains(matched=True, build_targets={'exe'})
229
230# Various permutations when passing in targets.
231_CreateConfigFile(['exe2.c', 'subdir/subdir2b_source.c'], ['exe', 'exe3'])
232run_analyzer()
233EnsureContains(matched=True, targets={'exe3'}, build_targets={'exe2', 'exe3'})
234
235_CreateConfigFile(['exe2.c', 'subdir/subdir2b_source.c'], ['exe'])
236run_analyzer()
237EnsureContains(matched=True, build_targets={'exe2', 'exe3'})
238
239# Verifies duplicates are ignored.
240_CreateConfigFile(['exe2.c', 'subdir/subdir2b_source.c'], ['exe', 'exe'])
241run_analyzer()
242EnsureContains(matched=True, build_targets={'exe2', 'exe3'})
243
244_CreateConfigFile(['exe2.c'], ['exe'])
245run_analyzer()
246EnsureContains(matched=True, build_targets={'exe2'})
247
248_CreateConfigFile(['exe2.c'], [])
249run_analyzer()
250EnsureContains(matched=True, build_targets={'exe2'})
251
252_CreateConfigFile(['subdir/subdir2b_source.c', 'exe2.c'], [])
253run_analyzer()
254EnsureContains(matched=True, build_targets={'exe2', 'exe3'})
255
256_CreateConfigFile(['subdir/subdir2b_source.c'], ['exe3'])
257run_analyzer()
258EnsureContains(matched=True, targets={'exe3'}, build_targets={'exe3'})
259
260_CreateConfigFile(['exe2.c'], [])
261run_analyzer()
262EnsureContains(matched=True, build_targets={'exe2'})
263
264_CreateConfigFile(['foo.c'], [])
265run_analyzer()
266EnsureContains(matched=True, build_targets={'exe'})
267
268# Assertions when modifying build (gyp/gypi) files, especially when said files
269# are included.
270_CreateConfigFile(['subdir2/d.cc'], ['exe', 'exe2', 'foo', 'exe3'])
271run_analyzer2()
272EnsureContains(matched=True, targets={'exe', 'foo'}, build_targets={'exe'})
273
274_CreateConfigFile(['subdir2/subdir.includes.gypi'],
275                ['exe', 'exe2', 'foo', 'exe3'])
276run_analyzer2()
277EnsureContains(matched=True, targets={'exe', 'foo'}, build_targets={'exe'})
278
279_CreateConfigFile(['subdir2/subdir.gyp'], ['exe', 'exe2', 'foo', 'exe3'])
280run_analyzer2()
281EnsureContains(matched=True, targets={'exe', 'foo'}, build_targets={'exe'})
282
283_CreateConfigFile(['test2.includes.gypi'], ['exe', 'exe2', 'foo', 'exe3'])
284run_analyzer2()
285EnsureContains(matched=True, targets={'exe', 'exe2', 'exe3'},
286               build_targets={'exe', 'exe2', 'exe3'})
287
288# Verify modifying a file included makes all targets dirty.
289_CreateConfigFile(['common.gypi'], ['exe', 'exe2', 'foo', 'exe3'])
290run_analyzer2('-Icommon.gypi')
291EnsureMatchedAll({'exe', 'exe2', 'foo', 'exe3'})
292
293# Assertions from test3.gyp.
294_CreateConfigFile(['d.c', 'f.c'], ['a'])
295run_analyzer3()
296EnsureContains(matched=True, targets={'a'}, build_targets={'a', 'b'})
297
298_CreateConfigFile(['f.c'], ['a'])
299run_analyzer3()
300EnsureContains(matched=True, targets={'a'}, build_targets={'a', 'b'})
301
302_CreateConfigFile(['f.c'], [])
303run_analyzer3()
304EnsureContains(matched=True, build_targets={'a', 'b'})
305
306_CreateConfigFile(['c.c', 'e.c'], [])
307run_analyzer3()
308EnsureContains(matched=True, build_targets={'a', 'b', 'c', 'e'})
309
310_CreateConfigFile(['d.c'], ['a'])
311run_analyzer3()
312EnsureContains(matched=True, targets={'a'}, build_targets={'a', 'b'})
313
314_CreateConfigFile(['a.c'], ['a', 'b'])
315run_analyzer3()
316EnsureContains(matched=True, targets={'a'}, build_targets={'a'})
317
318_CreateConfigFile(['a.c'], ['a', 'b'])
319run_analyzer3()
320EnsureContains(matched=True, targets={'a'}, build_targets={'a'})
321
322_CreateConfigFile(['d.c'], ['a', 'b'])
323run_analyzer3()
324EnsureContains(matched=True, targets={'a', 'b'}, build_targets={'a', 'b'})
325
326_CreateConfigFile(['f.c'], ['a'])
327run_analyzer3()
328EnsureContains(matched=True, targets={'a'}, build_targets={'a', 'b'})
329
330_CreateConfigFile(['a.c'], ['a'])
331run_analyzer3()
332EnsureContains(matched=True, targets={'a'}, build_targets={'a'})
333
334_CreateConfigFile(['a.c'], [])
335run_analyzer3()
336EnsureContains(matched=True, build_targets={'a'})
337
338_CreateConfigFile(['d.c'], [])
339run_analyzer3()
340EnsureContains(matched=True, build_targets={'a', 'b'})
341
342# Assertions around test4.gyp.
343_CreateConfigFile(['f.c'], [])
344run_analyzer4()
345EnsureContains(matched=True, build_targets={'e', 'f'})
346
347_CreateConfigFile(['d.c'], [])
348run_analyzer4()
349EnsureContains(matched=True, build_targets={'a', 'b', 'c', 'd'})
350
351_CreateConfigFile(['i.c'], [])
352run_analyzer4()
353EnsureContains(matched=True, build_targets={'h'})
354
355test.pass_test()
356