Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(143)

Side by Side Diff: tools/code_coverage/croc_test.py

Issue 113346: Add croc code coverage tool. (Same change as yesterday, but now made in the... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/code_coverage/croc.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/python2.4
2 #
3 # Copyright 2009, Google Inc.
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions are
8 # met:
9 #
10 # * Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # * Redistributions in binary form must reproduce the above
13 # copyright notice, this list of conditions and the following disclaimer
14 # in the documentation and/or other materials provided with the
15 # distribution.
16 # * Neither the name of Google Inc. nor the names of its
17 # contributors may be used to endorse or promote products derived from
18 # this software without specific prior written permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 """Unit tests for Crocodile."""
33
34 import os
35 import re
36 import sys
37 import StringIO
38 import unittest
39 import croc
40
41 #------------------------------------------------------------------------------
42
43 class TestCoverageStats(unittest.TestCase):
44 """Tests for croc.CoverageStats."""
45
46 def testAdd(self):
47 """Test Add()."""
48 c = croc.CoverageStats()
49
50 # Initially empty
51 self.assertEqual(c, {})
52
53 # Add items
54 c['a'] = 1
55 c['b'] = 0
56 self.assertEqual(c, {'a':1, 'b':0})
57
58 # Add dict with non-overlapping items
59 c.Add({'c':5})
60 self.assertEqual(c, {'a':1, 'b':0, 'c':5})
61
62 # Add dict with overlapping items
63 c.Add({'a':4, 'd':3})
64 self.assertEqual(c, {'a':5, 'b':0, 'c':5, 'd':3})
65
66 #------------------------------------------------------------------------------
67
68 class TestCoveredFile(unittest.TestCase):
69 """Tests for croc.CoveredFile."""
70
71 def setUp(self):
72 self.cov_file = croc.CoveredFile('bob.cc', 'source', 'C++')
73
74 def testInit(self):
75 """Test init."""
76 f = self.cov_file
77
78 # Check initial values
79 self.assertEqual(f.filename, 'bob.cc')
80 self.assertEqual(f.group, 'source')
81 self.assertEqual(f.language, 'C++')
82 self.assertEqual(f.lines, {})
83 self.assertEqual(f.stats, {})
84
85 def testUpdateCoverageEmpty(self):
86 """Test updating coverage when empty."""
87 f = self.cov_file
88 f.UpdateCoverage()
89 self.assertEqual(f.stats, {
90 'lines_executable':0,
91 'lines_instrumented':0,
92 'lines_covered':0,
93 'files_executable':1,
94 })
95
96 def testUpdateCoverageExeOnly(self):
97 """Test updating coverage when no lines are instrumented."""
98 f = self.cov_file
99 f.lines = {1:None, 2:None, 4:None}
100 f.UpdateCoverage()
101 self.assertEqual(f.stats, {
102 'lines_executable':3,
103 'lines_instrumented':0,
104 'lines_covered':0,
105 'files_executable':1,
106 })
107
108 def testUpdateCoverageExeAndInstr(self):
109 """Test updating coverage when no lines are covered."""
110 f = self.cov_file
111 f.lines = {1:None, 2:None, 4:0, 5:0, 7:None}
112 f.UpdateCoverage()
113 self.assertEqual(f.stats, {
114 'lines_executable':5,
115 'lines_instrumented':2,
116 'lines_covered':0,
117 'files_executable':1,
118 'files_instrumented':1,
119 })
120
121 def testUpdateCoverageWhenCovered(self):
122 """Test updating coverage when lines are covered."""
123 f = self.cov_file
124 f.lines = {1:None, 2:None, 3:1, 4:0, 5:0, 6:1, 7:None}
125 f.UpdateCoverage()
126 self.assertEqual(f.stats, {
127 'lines_executable':7,
128 'lines_instrumented':4,
129 'lines_covered':2,
130 'files_executable':1,
131 'files_instrumented':1,
132 'files_covered':1,
133 })
134
135 #------------------------------------------------------------------------------
136
137 class TestCoveredDir(unittest.TestCase):
138 """Tests for croc.CoveredDir."""
139
140 def setUp(self):
141 self.cov_dir = croc.CoveredDir('/a/b/c')
142
143 def testInit(self):
144 """Test init."""
145 d = self.cov_dir
146
147 # Check initial values
148 self.assertEqual(d.dirpath, '/a/b/c')
149 self.assertEqual(d.files, {})
150 self.assertEqual(d.subdirs, {})
151 self.assertEqual(d.stats_by_group, {'all':{}})
152
153 def testGetTreeEmpty(self):
154 """Test getting empty tree."""
155 d = self.cov_dir
156 self.assertEqual(d.GetTree(), '/a/b/c/')
157
158 def testGetTreeStats(self):
159 """Test getting tree with stats."""
160 d = self.cov_dir
161 d.stats_by_group['all'] = croc.CoverageStats(
162 lines_executable=50, lines_instrumented=30, lines_covered=20)
163 d.stats_by_group['bar'] = croc.CoverageStats(
164 lines_executable=0, lines_instrumented=0, lines_covered=0)
165 d.stats_by_group['foo'] = croc.CoverageStats(
166 lines_executable=33, lines_instrumented=22, lines_covered=11)
167 # 'bar' group is skipped because it has no executable lines
168 self.assertEqual(d.GetTree(),
169 '/a/b/c/ all:20/30/50 foo:11/22/33')
170
171 def testGetTreeSubdir(self):
172 """Test getting tree with subdirs."""
173 d1 = self.cov_dir = croc.CoveredDir('/a')
174 d2 = self.cov_dir = croc.CoveredDir('/a/b')
175 d3 = self.cov_dir = croc.CoveredDir('/a/c')
176 d4 = self.cov_dir = croc.CoveredDir('/a/b/d')
177 d5 = self.cov_dir = croc.CoveredDir('/a/b/e')
178 d1.subdirs = {'/a/b':d2, '/a/c':d3}
179 d2.subdirs = {'/a/b/d':d4, '/a/b/e':d5}
180 self.assertEqual(d1.GetTree(),
181 '/a/\n /a/b/\n /a/b/d/\n /a/b/e/\n /a/c/')
182
183 #------------------------------------------------------------------------------
184
185 class TestCoverage(unittest.TestCase):
186 """Tests for croc.Coverage."""
187
188 def MockWalk(self, src_dir):
189 """Mock for os.walk().
190
191 Args:
192 src_dir: Source directory to walk.
193
194 Returns:
195 A list of (dirpath, dirnames, filenames) tuples.
196 """
197 self.mock_walk_calls.append(src_dir)
198 return self.mock_walk_return
199
200 def setUp(self):
201 """Per-test setup"""
202
203 # Empty coverage object
204 self.cov = croc.Coverage()
205
206 # Coverage object with minimal setup
207 self.cov_minimal = croc.Coverage()
208 self.cov_minimal.AddRoot('/src')
209 self.cov_minimal.AddRoot('c:\\source')
210 self.cov_minimal.AddRule('^#/', include=1, group='my')
211 self.cov_minimal.AddRule('.*\\.c$', language='C')
212 self.cov_minimal.AddRule('.*\\.c##$', language='C##') # sharper than thou
213
214 # Data for MockWalk()
215 self.mock_walk_calls = []
216 self.mock_walk_return = []
217
218 def testInit(self):
219 """Test init."""
220 c = self.cov
221 self.assertEqual(c.files, {})
222 self.assertEqual(c.root_dirs, [])
223 self.assertEqual(c.print_stats, [])
224
225 # Check for the initial subdir rule
226 self.assertEqual(len(c.rules), 1)
227 r0 = c.rules[0]
228 self.assertEqual(r0[0].pattern, '.*/$')
229 self.assertEqual(r0[1:], [None, None, 'subdir'])
230
231 def testAddRoot(self):
232 """Test AddRoot() and CleanupFilename()."""
233 c = self.cov
234
235 # Check for identity on already-clean filenames
236 self.assertEqual(c.CleanupFilename(''), '')
237 self.assertEqual(c.CleanupFilename('a'), 'a')
238 self.assertEqual(c.CleanupFilename('.a'), '.a')
239 self.assertEqual(c.CleanupFilename('..a'), '..a')
240 self.assertEqual(c.CleanupFilename('a.b'), 'a.b')
241 self.assertEqual(c.CleanupFilename('a/b/c'), 'a/b/c')
242 self.assertEqual(c.CleanupFilename('a/b/c/'), 'a/b/c/')
243
244 # Backslash to forward slash
245 self.assertEqual(c.CleanupFilename('a\\b\\c'), 'a/b/c')
246
247 # Handle relative paths
248 self.assertEqual(c.CleanupFilename('.'),
249 c.CleanupFilename(os.path.abspath('.')))
250 self.assertEqual(c.CleanupFilename('..'),
251 c.CleanupFilename(os.path.abspath('..')))
252 self.assertEqual(c.CleanupFilename('./foo/bar'),
253 c.CleanupFilename(os.path.abspath('./foo/bar')))
254 self.assertEqual(c.CleanupFilename('../../a/b/c'),
255 c.CleanupFilename(os.path.abspath('../../a/b/c')))
256
257 # Replace alt roots
258 c.AddRoot('foo', '#')
259 self.assertEqual(c.CleanupFilename('foo'), '#')
260 self.assertEqual(c.CleanupFilename('foo/bar/baz'), '#/bar/baz')
261 self.assertEqual(c.CleanupFilename('aaa/foo'), 'aaa/foo')
262
263 # Alt root replacement is applied for all roots
264 c.AddRoot('foo/bar', '#B')
265 self.assertEqual(c.CleanupFilename('foo/bar/baz'), '#B/baz')
266
267 # Can use previously defined roots in cleanup
268 c.AddRoot('#/nom/nom/nom', '#CANHAS')
269 self.assertEqual(c.CleanupFilename('foo/nom/nom/nom/cheezburger'),
270 '#CANHAS/cheezburger')
271
272 # Verify roots starting with UNC paths or drive letters work, and that
273 # more than one root can point to the same alt_name
274 c.AddRoot('/usr/local/foo', '#FOO')
275 c.AddRoot('D:\\my\\foo', '#FOO')
276 self.assertEqual(c.CleanupFilename('/usr/local/foo/a/b'), '#FOO/a/b')
277 self.assertEqual(c.CleanupFilename('D:\\my\\foo\\c\\d'), '#FOO/c/d')
278
279 def testAddRule(self):
280 """Test AddRule() and ClassifyFile()."""
281 c = self.cov
282
283 # With only the default rule, nothing gets kept
284 self.assertEqual(c.ClassifyFile('#/src/'), (None, None))
285 self.assertEqual(c.ClassifyFile('#/src/a.c'), (None, None))
286
287 # Add rules to include a tree and set a default group
288 c.AddRule('^#/src/', include=1, group='source')
289 # Now the subdir matches, but source doesn't, since no languages are
290 # defined yet
291 self.assertEqual(c.ClassifyFile('#/src/'), ('source', 'subdir'))
292 self.assertEqual(c.ClassifyFile('#/notsrc/'), (None, None))
293 self.assertEqual(c.ClassifyFile('#/src/a.c'), (None, None))
294
295 # Define some languages and groups
296 c.AddRule('.*\\.(c|h)$', language='C')
297 c.AddRule('.*\\.py$', language='Python')
298 c.AddRule('.*_test\\.', group='test')
299 self.assertEqual(c.ClassifyFile('#/src/a.c'), ('source', 'C'))
300 self.assertEqual(c.ClassifyFile('#/src/a.h'), ('source', 'C'))
301 self.assertEqual(c.ClassifyFile('#/src/a.cpp'), (None, None))
302 self.assertEqual(c.ClassifyFile('#/src/a_test.c'), ('test', 'C'))
303 self.assertEqual(c.ClassifyFile('#/src/test_a.c'), ('source', 'C'))
304 self.assertEqual(c.ClassifyFile('#/src/foo/bar.py'), ('source', 'Python'))
305 self.assertEqual(c.ClassifyFile('#/src/test.py'), ('source', 'Python'))
306
307 # Exclude a path (for example, anything in a build output dir)
308 c.AddRule('.*/build/', include=0)
309 # But add back in a dir which matched the above rule but isn't a build
310 # output dir
311 c.AddRule('#/src/tools/build/', include=1)
312 self.assertEqual(c.ClassifyFile('#/src/build.c'), ('source', 'C'))
313 self.assertEqual(c.ClassifyFile('#/src/build/'), (None, None))
314 self.assertEqual(c.ClassifyFile('#/src/build/a.c'), (None, None))
315 self.assertEqual(c.ClassifyFile('#/src/tools/build/'), ('source', 'subdir'))
316 self.assertEqual(c.ClassifyFile('#/src/tools/build/t.c'), ('source', 'C'))
317
318 def testGetCoveredFile(self):
319 """Test GetCoveredFile()."""
320 c = self.cov_minimal
321
322 # Not currently any covered files
323 self.assertEqual(c.GetCoveredFile('#/a.c'), None)
324
325 # Add some files
326 a_c = c.GetCoveredFile('#/a.c', add=True)
327 b_c = c.GetCoveredFile('#/b.c##', add=True)
328 self.assertEqual(a_c.filename, '#/a.c')
329 self.assertEqual(a_c.group, 'my')
330 self.assertEqual(a_c.language, 'C')
331 self.assertEqual(b_c.filename, '#/b.c##')
332 self.assertEqual(b_c.group, 'my')
333 self.assertEqual(b_c.language, 'C##')
334
335 # Specifying the same filename should return the existing object
336 self.assertEqual(c.GetCoveredFile('#/a.c'), a_c)
337 self.assertEqual(c.GetCoveredFile('#/a.c', add=True), a_c)
338
339 # Filenames get cleaned on the way in, as do root paths
340 self.assertEqual(c.GetCoveredFile('/src/a.c'), a_c)
341 self.assertEqual(c.GetCoveredFile('c:\\source\\a.c'), a_c)
342
343 def testParseLcov(self):
344 """Test ParseLcovData()."""
345 c = self.cov_minimal
346
347 c.ParseLcovData([
348 '# Ignore unknown lines',
349 # File we should include'
350 'SF:/src/a.c',
351 'DA:10,1',
352 'DA:11,0',
353 'DA:12,1 \n', # Trailing whitespace should get stripped
354 'end_of_record',
355 # File we should ignore
356 'SF:/not_src/a.c',
357 'DA:20,1',
358 'end_of_record',
359 # Same as first source file, but alternate root
360 'SF:c:\\source\\a.c',
361 'DA:30,1',
362 'end_of_record',
363 # Ignore extra end of record
364 'end_of_record',
365 # Ignore data points after end of record
366 'DA:40,1',
367 # Instrumented but uncovered file
368 'SF:/src/b.c',
369 'DA:50,0',
370 'end_of_record',
371 ])
372
373 # We should know about two files
374 self.assertEqual(sorted(c.files), ['#/a.c', '#/b.c'])
375
376 # Check expected contents
377 a_c = c.GetCoveredFile('#/a.c')
378 self.assertEqual(a_c.lines, {10: 1, 11: 0, 12: 1, 30: 1})
379 self.assertEqual(a_c.stats, {
380 'files_executable': 1,
381 'files_instrumented': 1,
382 'files_covered': 1,
383 'lines_instrumented': 4,
384 'lines_executable': 4,
385 'lines_covered': 3,
386 })
387 b_c = c.GetCoveredFile('#/b.c')
388 self.assertEqual(b_c.lines, {50: 0})
389 self.assertEqual(b_c.stats, {
390 'files_executable': 1,
391 'files_instrumented': 1,
392 'lines_instrumented': 1,
393 'lines_executable': 1,
394 'lines_covered': 0,
395 })
396
397 def testGetStat(self):
398 """Test GetStat() and PrintStat()."""
399 c = self.cov
400
401 # Add some stats, so there's something to report
402 c.tree.stats_by_group = {
403 'all': {
404 'count_a': 10,
405 'count_b': 4,
406 'foo': 'bar',
407 },
408 'tests': {
409 'count_a': 2,
410 'count_b': 5,
411 'baz': 'bob',
412 },
413 }
414
415 # Test missing stats and groups
416 self.assertRaises(croc.CoverageStatError, c.GetStat, 'nosuch')
417 self.assertRaises(croc.CoverageStatError, c.GetStat, 'baz')
418 self.assertRaises(croc.CoverageStatError, c.GetStat, 'foo', group='tests')
419 self.assertRaises(croc.CoverageStatError, c.GetStat, 'foo', group='nosuch')
420
421 # Test returning defaults
422 self.assertEqual(c.GetStat('nosuch', default=13), 13)
423 self.assertEqual(c.GetStat('baz', default='aaa'), 'aaa')
424 self.assertEqual(c.GetStat('foo', group='tests', default=0), 0)
425 self.assertEqual(c.GetStat('foo', group='nosuch', default=''), '')
426
427 # Test getting stats
428 self.assertEqual(c.GetStat('count_a'), 10)
429 self.assertEqual(c.GetStat('count_a', group='tests'), 2)
430 self.assertEqual(c.GetStat('foo', default='baz'), 'bar')
431
432 # Test stat math (eval)
433 self.assertEqual(c.GetStat('count_a - count_b'), 6)
434 self.assertEqual(c.GetStat('100.0 * count_a / count_b', group='tests'),
435 40.0)
436 # Should catch eval errors
437 self.assertRaises(croc.CoverageStatError, c.GetStat, '100 / 0')
438 self.assertRaises(croc.CoverageStatError, c.GetStat, 'count_a -')
439
440 # Test nested stats via S()
441 self.assertEqual(c.GetStat('count_a - S("count_a", group="tests")'), 8)
442 self.assertRaises(croc.CoverageStatError, c.GetStat, 'S()')
443 self.assertRaises(croc.CoverageStatError, c.GetStat, 'S("nosuch")')
444
445 # Test PrintStat()
446 # We won't see the first print, but at least verify it doesn't assert
447 c.PrintStat('count_a', format='(test to stdout: %s)')
448 # Send subsequent prints to a file
449 f = StringIO.StringIO()
450 c.PrintStat('count_b', outfile=f)
451 # Test specifying output format
452 c.PrintStat('count_a', format='Count A = %05d', outfile=f)
453 # Test specifing additional keyword args
454 c.PrintStat('count_a', group='tests', outfile=f)
455 c.PrintStat('nosuch', default=42, outfile=f)
456 self.assertEqual(f.getvalue(), ("""\
457 GetStat('count_b') = 4
458 Count A = 00010
459 GetStat('count_a') = 2
460 GetStat('nosuch') = 42
461 """))
462 f.close()
463
464 def testAddConfigEmpty(self):
465 """Test AddConfig() with empty config."""
466 c = self.cov
467 # Most minimal config is an empty dict; should do nothing
468 c.AddConfig('{} # And we ignore comments')
469
470 def testAddConfig(self):
471 """Test AddConfig()."""
472 c = self.cov
473 lcov_queue = []
474 addfiles_queue = []
475
476 c.AddConfig("""{
477 'roots' : [
478 {'root' : '/foo'},
479 {'root' : '/bar', 'altname' : '#BAR'},
480 ],
481 'rules' : [
482 {'regexp' : '^#', 'group' : 'apple'},
483 {'regexp' : 're2', 'include' : 1, 'language' : 'elvish'},
484 ],
485 'lcov_files' : ['a.lcov', 'b.lcov'],
486 'add_files' : ['/src', '#BAR/doo'],
487 'print_stats' : [
488 {'stat' : 'count_a'},
489 {'stat' : 'count_b', 'group' : 'tests'},
490 ],
491 'extra_key' : 'is ignored',
492 }""", lcov_queue=lcov_queue, addfiles_queue=addfiles_queue)
493
494 self.assertEqual(lcov_queue, ['a.lcov', 'b.lcov'])
495 self.assertEqual(addfiles_queue, ['/src', '#BAR/doo'])
496 self.assertEqual(c.root_dirs, [['/foo', '#'], ['/bar', '#BAR']])
497 self.assertEqual(c.print_stats, [
498 {'stat': 'count_a'},
499 {'stat': 'count_b', 'group': 'tests'},
500 ])
501 # Convert compiled re's back to patterns for comparison
502 rules = [[r[0].pattern] + r[1:] for r in c.rules]
503 self.assertEqual(rules, [
504 ['.*/$', None, None, 'subdir'],
505 ['^#', None, 'apple', None],
506 ['re2', 1, None, 'elvish'],
507 ])
508
509 def testAddFilesSimple(self):
510 """Test AddFiles() simple call."""
511 c = self.cov_minimal
512 c.add_files_walk = self.MockWalk
513 c.AddFiles('/a/b/c')
514 self.assertEqual(self.mock_walk_calls, ['/a/b/c'])
515 self.assertEqual(c.files, {})
516
517 def testAddFilesRootMap(self):
518 """Test AddFiles() with root mappings."""
519 c = self.cov_minimal
520 c.add_files_walk = self.MockWalk
521 c.AddRoot('#/subdir', '#SUBDIR')
522
523 # AddFiles() should replace the '#SUBDIR' alt_name, then match both
524 # possible roots for the '#' alt_name.
525 c.AddFiles('#SUBDIR/foo')
526 self.assertEqual(self.mock_walk_calls,
527 ['/src/subdir/foo', 'c:/source/subdir/foo'])
528 self.assertEqual(c.files, {})
529
530 def testAddFilesNonEmpty(self):
531 """Test AddFiles() where files are returned."""
532
533 c = self.cov_minimal
534 c.add_files_walk = self.MockWalk
535
536 # Add a rule to exclude a subdir
537 c.AddRule('^#/proj1/excluded/', include=0)
538
539 # Set data for mock walk
540 self.mock_walk_return = [
541 [
542 '/src/proj1',
543 ['excluded', 'subdir'],
544 ['a.c', 'no.f', 'yes.c'],
545 ],
546 [
547 '/src/proj1/subdir',
548 [],
549 ['cherry.c'],
550 ],
551 ]
552
553 c.AddFiles('/src/proj1')
554
555 self.assertEqual(self.mock_walk_calls, ['/src/proj1'])
556
557 # Include files from the main dir and subdir
558 self.assertEqual(sorted(c.files), [
559 '#/proj1/a.c',
560 '#/proj1/subdir/cherry.c',
561 '#/proj1/yes.c'])
562
563 # Excluded dir should have been pruned from the mock walk data dirnames.
564 # In the real os.walk() call this prunes the walk.
565 self.assertEqual(self.mock_walk_return[0][1], ['subdir'])
566
567 def testUpdateTreeStats(self):
568 """Test UpdateTreeStats()."""
569
570 c = self.cov_minimal
571
572
573
574 c.AddRule('.*_test', group='test')
575
576 # Fill the files list
577 c.ParseLcovData([
578 'SF:/src/a.c',
579 'DA:10,1', 'DA:11,1', 'DA:20,0',
580 'end_of_record',
581 'SF:/src/a_test.c',
582 'DA:10,1', 'DA:11,1', 'DA:12,1',
583 'end_of_record',
584 'SF:/src/foo/b.c',
585 'DA:10,1', 'DA:11,1', 'DA:20,0', 'DA:21,0', 'DA:30,0',
586 'end_of_record',
587 'SF:/src/foo/b_test.c',
588 'DA:20,0', 'DA:21,0', 'DA:22,0',
589 'end_of_record',
590 ])
591 c.UpdateTreeStats()
592
593 t = c.tree
594 self.assertEqual(t.dirpath, '')
595 self.assertEqual(sorted(t.files), [])
596 self.assertEqual(sorted(t.subdirs), ['#'])
597 self.assertEqual(t.stats_by_group, {
598 'all': {
599 'files_covered': 3,
600 'files_executable': 4,
601 'lines_executable': 14,
602 'lines_covered': 7,
603 'lines_instrumented': 14,
604 'files_instrumented': 4,
605 },
606 'my': {
607 'files_covered': 2,
608 'files_executable': 2,
609 'lines_executable': 8,
610 'lines_covered': 4,
611 'lines_instrumented': 8,
612 'files_instrumented': 2,
613 },
614 'test': {
615 'files_covered': 1,
616 'files_executable': 2,
617 'lines_executable': 6,
618 'lines_covered': 3,
619 'lines_instrumented': 6,
620 'files_instrumented': 2,
621 },
622 })
623
624 t = t.subdirs['#']
625 self.assertEqual(t.dirpath, '#')
626 self.assertEqual(sorted(t.files), ['a.c', 'a_test.c'])
627 self.assertEqual(sorted(t.subdirs), ['foo'])
628 self.assertEqual(t.stats_by_group, {
629 'all': {
630 'files_covered': 3,
631 'files_executable': 4,
632 'lines_executable': 14,
633 'lines_covered': 7,
634 'lines_instrumented': 14,
635 'files_instrumented': 4,
636 },
637 'my': {
638 'files_covered': 2,
639 'files_executable': 2,
640 'lines_executable': 8,
641 'lines_covered': 4,
642 'lines_instrumented': 8,
643 'files_instrumented': 2,
644 },
645 'test': {
646 'files_covered': 1,
647 'files_executable': 2,
648 'lines_executable': 6,
649 'lines_covered': 3,
650 'lines_instrumented': 6,
651 'files_instrumented': 2,
652 },
653 })
654
655 t = t.subdirs['foo']
656 self.assertEqual(t.dirpath, 'foo')
657 self.assertEqual(sorted(t.files), ['b.c', 'b_test.c'])
658 self.assertEqual(sorted(t.subdirs), [])
659 self.assertEqual(t.stats_by_group, {
660 'test': {
661 'files_executable': 1,
662 'files_instrumented': 1,
663 'lines_executable': 3,
664 'lines_instrumented': 3,
665 'lines_covered': 0,
666 },
667 'all': {
668 'files_covered': 1,
669 'files_executable': 2,
670 'lines_executable': 8,
671 'lines_covered': 2,
672 'lines_instrumented': 8,
673 'files_instrumented': 2,
674 },
675 'my': {
676 'files_covered': 1,
677 'files_executable': 1,
678 'lines_executable': 5,
679 'lines_covered': 2,
680 'lines_instrumented': 5,
681 'files_instrumented': 1,
682 }
683 })
684
685 # TODO: test: less important, since these are thin wrappers around other
686 # tested methods.
687 # ParseConfig()
688 # ParseLcovFile()
689 # PrintTree()
690
691 #------------------------------------------------------------------------------
692
693 if __name__ == '__main__':
694 unittest.main()
OLDNEW
« no previous file with comments | « tools/code_coverage/croc.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698