| Index: tools/code_coverage/croc_test.py
|
| ===================================================================
|
| --- tools/code_coverage/croc_test.py (revision 0)
|
| +++ tools/code_coverage/croc_test.py (revision 0)
|
| @@ -0,0 +1,694 @@
|
| +#!/usr/bin/python2.4
|
| +#
|
| +# Copyright 2009, Google Inc.
|
| +# All rights reserved.
|
| +#
|
| +# Redistribution and use in source and binary forms, with or without
|
| +# modification, are permitted provided that the following conditions are
|
| +# met:
|
| +#
|
| +# * Redistributions of source code must retain the above copyright
|
| +# notice, this list of conditions and the following disclaimer.
|
| +# * Redistributions in binary form must reproduce the above
|
| +# copyright notice, this list of conditions and the following disclaimer
|
| +# in the documentation and/or other materials provided with the
|
| +# distribution.
|
| +# * Neither the name of Google Inc. nor the names of its
|
| +# contributors may be used to endorse or promote products derived from
|
| +# this software without specific prior written permission.
|
| +#
|
| +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| +
|
| +"""Unit tests for Crocodile."""
|
| +
|
| +import os
|
| +import re
|
| +import sys
|
| +import StringIO
|
| +import unittest
|
| +import croc
|
| +
|
| +#------------------------------------------------------------------------------
|
| +
|
| +class TestCoverageStats(unittest.TestCase):
|
| + """Tests for croc.CoverageStats."""
|
| +
|
| + def testAdd(self):
|
| + """Test Add()."""
|
| + c = croc.CoverageStats()
|
| +
|
| + # Initially empty
|
| + self.assertEqual(c, {})
|
| +
|
| + # Add items
|
| + c['a'] = 1
|
| + c['b'] = 0
|
| + self.assertEqual(c, {'a':1, 'b':0})
|
| +
|
| + # Add dict with non-overlapping items
|
| + c.Add({'c':5})
|
| + self.assertEqual(c, {'a':1, 'b':0, 'c':5})
|
| +
|
| + # Add dict with overlapping items
|
| + c.Add({'a':4, 'd':3})
|
| + self.assertEqual(c, {'a':5, 'b':0, 'c':5, 'd':3})
|
| +
|
| +#------------------------------------------------------------------------------
|
| +
|
| +class TestCoveredFile(unittest.TestCase):
|
| + """Tests for croc.CoveredFile."""
|
| +
|
| + def setUp(self):
|
| + self.cov_file = croc.CoveredFile('bob.cc', 'source', 'C++')
|
| +
|
| + def testInit(self):
|
| + """Test init."""
|
| + f = self.cov_file
|
| +
|
| + # Check initial values
|
| + self.assertEqual(f.filename, 'bob.cc')
|
| + self.assertEqual(f.group, 'source')
|
| + self.assertEqual(f.language, 'C++')
|
| + self.assertEqual(f.lines, {})
|
| + self.assertEqual(f.stats, {})
|
| +
|
| + def testUpdateCoverageEmpty(self):
|
| + """Test updating coverage when empty."""
|
| + f = self.cov_file
|
| + f.UpdateCoverage()
|
| + self.assertEqual(f.stats, {
|
| + 'lines_executable':0,
|
| + 'lines_instrumented':0,
|
| + 'lines_covered':0,
|
| + 'files_executable':1,
|
| + })
|
| +
|
| + def testUpdateCoverageExeOnly(self):
|
| + """Test updating coverage when no lines are instrumented."""
|
| + f = self.cov_file
|
| + f.lines = {1:None, 2:None, 4:None}
|
| + f.UpdateCoverage()
|
| + self.assertEqual(f.stats, {
|
| + 'lines_executable':3,
|
| + 'lines_instrumented':0,
|
| + 'lines_covered':0,
|
| + 'files_executable':1,
|
| + })
|
| +
|
| + def testUpdateCoverageExeAndInstr(self):
|
| + """Test updating coverage when no lines are covered."""
|
| + f = self.cov_file
|
| + f.lines = {1:None, 2:None, 4:0, 5:0, 7:None}
|
| + f.UpdateCoverage()
|
| + self.assertEqual(f.stats, {
|
| + 'lines_executable':5,
|
| + 'lines_instrumented':2,
|
| + 'lines_covered':0,
|
| + 'files_executable':1,
|
| + 'files_instrumented':1,
|
| + })
|
| +
|
| + def testUpdateCoverageWhenCovered(self):
|
| + """Test updating coverage when lines are covered."""
|
| + f = self.cov_file
|
| + f.lines = {1:None, 2:None, 3:1, 4:0, 5:0, 6:1, 7:None}
|
| + f.UpdateCoverage()
|
| + self.assertEqual(f.stats, {
|
| + 'lines_executable':7,
|
| + 'lines_instrumented':4,
|
| + 'lines_covered':2,
|
| + 'files_executable':1,
|
| + 'files_instrumented':1,
|
| + 'files_covered':1,
|
| + })
|
| +
|
| +#------------------------------------------------------------------------------
|
| +
|
| +class TestCoveredDir(unittest.TestCase):
|
| + """Tests for croc.CoveredDir."""
|
| +
|
| + def setUp(self):
|
| + self.cov_dir = croc.CoveredDir('/a/b/c')
|
| +
|
| + def testInit(self):
|
| + """Test init."""
|
| + d = self.cov_dir
|
| +
|
| + # Check initial values
|
| + self.assertEqual(d.dirpath, '/a/b/c')
|
| + self.assertEqual(d.files, {})
|
| + self.assertEqual(d.subdirs, {})
|
| + self.assertEqual(d.stats_by_group, {'all':{}})
|
| +
|
| + def testGetTreeEmpty(self):
|
| + """Test getting empty tree."""
|
| + d = self.cov_dir
|
| + self.assertEqual(d.GetTree(), '/a/b/c/')
|
| +
|
| + def testGetTreeStats(self):
|
| + """Test getting tree with stats."""
|
| + d = self.cov_dir
|
| + d.stats_by_group['all'] = croc.CoverageStats(
|
| + lines_executable=50, lines_instrumented=30, lines_covered=20)
|
| + d.stats_by_group['bar'] = croc.CoverageStats(
|
| + lines_executable=0, lines_instrumented=0, lines_covered=0)
|
| + d.stats_by_group['foo'] = croc.CoverageStats(
|
| + lines_executable=33, lines_instrumented=22, lines_covered=11)
|
| + # 'bar' group is skipped because it has no executable lines
|
| + self.assertEqual(d.GetTree(),
|
| + '/a/b/c/ all:20/30/50 foo:11/22/33')
|
| +
|
| + def testGetTreeSubdir(self):
|
| + """Test getting tree with subdirs."""
|
| + d1 = self.cov_dir = croc.CoveredDir('/a')
|
| + d2 = self.cov_dir = croc.CoveredDir('/a/b')
|
| + d3 = self.cov_dir = croc.CoveredDir('/a/c')
|
| + d4 = self.cov_dir = croc.CoveredDir('/a/b/d')
|
| + d5 = self.cov_dir = croc.CoveredDir('/a/b/e')
|
| + d1.subdirs = {'/a/b':d2, '/a/c':d3}
|
| + d2.subdirs = {'/a/b/d':d4, '/a/b/e':d5}
|
| + self.assertEqual(d1.GetTree(),
|
| + '/a/\n /a/b/\n /a/b/d/\n /a/b/e/\n /a/c/')
|
| +
|
| +#------------------------------------------------------------------------------
|
| +
|
| +class TestCoverage(unittest.TestCase):
|
| + """Tests for croc.Coverage."""
|
| +
|
| + def MockWalk(self, src_dir):
|
| + """Mock for os.walk().
|
| +
|
| + Args:
|
| + src_dir: Source directory to walk.
|
| +
|
| + Returns:
|
| + A list of (dirpath, dirnames, filenames) tuples.
|
| + """
|
| + self.mock_walk_calls.append(src_dir)
|
| + return self.mock_walk_return
|
| +
|
| + def setUp(self):
|
| + """Per-test setup"""
|
| +
|
| + # Empty coverage object
|
| + self.cov = croc.Coverage()
|
| +
|
| + # Coverage object with minimal setup
|
| + self.cov_minimal = croc.Coverage()
|
| + self.cov_minimal.AddRoot('/src')
|
| + self.cov_minimal.AddRoot('c:\\source')
|
| + self.cov_minimal.AddRule('^#/', include=1, group='my')
|
| + self.cov_minimal.AddRule('.*\\.c$', language='C')
|
| + self.cov_minimal.AddRule('.*\\.c##$', language='C##') # sharper than thou
|
| +
|
| + # Data for MockWalk()
|
| + self.mock_walk_calls = []
|
| + self.mock_walk_return = []
|
| +
|
| + def testInit(self):
|
| + """Test init."""
|
| + c = self.cov
|
| + self.assertEqual(c.files, {})
|
| + self.assertEqual(c.root_dirs, [])
|
| + self.assertEqual(c.print_stats, [])
|
| +
|
| + # Check for the initial subdir rule
|
| + self.assertEqual(len(c.rules), 1)
|
| + r0 = c.rules[0]
|
| + self.assertEqual(r0[0].pattern, '.*/$')
|
| + self.assertEqual(r0[1:], [None, None, 'subdir'])
|
| +
|
| + def testAddRoot(self):
|
| + """Test AddRoot() and CleanupFilename()."""
|
| + c = self.cov
|
| +
|
| + # Check for identity on already-clean filenames
|
| + self.assertEqual(c.CleanupFilename(''), '')
|
| + self.assertEqual(c.CleanupFilename('a'), 'a')
|
| + self.assertEqual(c.CleanupFilename('.a'), '.a')
|
| + self.assertEqual(c.CleanupFilename('..a'), '..a')
|
| + self.assertEqual(c.CleanupFilename('a.b'), 'a.b')
|
| + self.assertEqual(c.CleanupFilename('a/b/c'), 'a/b/c')
|
| + self.assertEqual(c.CleanupFilename('a/b/c/'), 'a/b/c/')
|
| +
|
| + # Backslash to forward slash
|
| + self.assertEqual(c.CleanupFilename('a\\b\\c'), 'a/b/c')
|
| +
|
| + # Handle relative paths
|
| + self.assertEqual(c.CleanupFilename('.'),
|
| + c.CleanupFilename(os.path.abspath('.')))
|
| + self.assertEqual(c.CleanupFilename('..'),
|
| + c.CleanupFilename(os.path.abspath('..')))
|
| + self.assertEqual(c.CleanupFilename('./foo/bar'),
|
| + c.CleanupFilename(os.path.abspath('./foo/bar')))
|
| + self.assertEqual(c.CleanupFilename('../../a/b/c'),
|
| + c.CleanupFilename(os.path.abspath('../../a/b/c')))
|
| +
|
| + # Replace alt roots
|
| + c.AddRoot('foo', '#')
|
| + self.assertEqual(c.CleanupFilename('foo'), '#')
|
| + self.assertEqual(c.CleanupFilename('foo/bar/baz'), '#/bar/baz')
|
| + self.assertEqual(c.CleanupFilename('aaa/foo'), 'aaa/foo')
|
| +
|
| + # Alt root replacement is applied for all roots
|
| + c.AddRoot('foo/bar', '#B')
|
| + self.assertEqual(c.CleanupFilename('foo/bar/baz'), '#B/baz')
|
| +
|
| + # Can use previously defined roots in cleanup
|
| + c.AddRoot('#/nom/nom/nom', '#CANHAS')
|
| + self.assertEqual(c.CleanupFilename('foo/nom/nom/nom/cheezburger'),
|
| + '#CANHAS/cheezburger')
|
| +
|
| + # Verify roots starting with UNC paths or drive letters work, and that
|
| + # more than one root can point to the same alt_name
|
| + c.AddRoot('/usr/local/foo', '#FOO')
|
| + c.AddRoot('D:\\my\\foo', '#FOO')
|
| + self.assertEqual(c.CleanupFilename('/usr/local/foo/a/b'), '#FOO/a/b')
|
| + self.assertEqual(c.CleanupFilename('D:\\my\\foo\\c\\d'), '#FOO/c/d')
|
| +
|
| + def testAddRule(self):
|
| + """Test AddRule() and ClassifyFile()."""
|
| + c = self.cov
|
| +
|
| + # With only the default rule, nothing gets kept
|
| + self.assertEqual(c.ClassifyFile('#/src/'), (None, None))
|
| + self.assertEqual(c.ClassifyFile('#/src/a.c'), (None, None))
|
| +
|
| + # Add rules to include a tree and set a default group
|
| + c.AddRule('^#/src/', include=1, group='source')
|
| + # Now the subdir matches, but source doesn't, since no languages are
|
| + # defined yet
|
| + self.assertEqual(c.ClassifyFile('#/src/'), ('source', 'subdir'))
|
| + self.assertEqual(c.ClassifyFile('#/notsrc/'), (None, None))
|
| + self.assertEqual(c.ClassifyFile('#/src/a.c'), (None, None))
|
| +
|
| + # Define some languages and groups
|
| + c.AddRule('.*\\.(c|h)$', language='C')
|
| + c.AddRule('.*\\.py$', language='Python')
|
| + c.AddRule('.*_test\\.', group='test')
|
| + self.assertEqual(c.ClassifyFile('#/src/a.c'), ('source', 'C'))
|
| + self.assertEqual(c.ClassifyFile('#/src/a.h'), ('source', 'C'))
|
| + self.assertEqual(c.ClassifyFile('#/src/a.cpp'), (None, None))
|
| + self.assertEqual(c.ClassifyFile('#/src/a_test.c'), ('test', 'C'))
|
| + self.assertEqual(c.ClassifyFile('#/src/test_a.c'), ('source', 'C'))
|
| + self.assertEqual(c.ClassifyFile('#/src/foo/bar.py'), ('source', 'Python'))
|
| + self.assertEqual(c.ClassifyFile('#/src/test.py'), ('source', 'Python'))
|
| +
|
| + # Exclude a path (for example, anything in a build output dir)
|
| + c.AddRule('.*/build/', include=0)
|
| + # But add back in a dir which matched the above rule but isn't a build
|
| + # output dir
|
| + c.AddRule('#/src/tools/build/', include=1)
|
| + self.assertEqual(c.ClassifyFile('#/src/build.c'), ('source', 'C'))
|
| + self.assertEqual(c.ClassifyFile('#/src/build/'), (None, None))
|
| + self.assertEqual(c.ClassifyFile('#/src/build/a.c'), (None, None))
|
| + self.assertEqual(c.ClassifyFile('#/src/tools/build/'), ('source', 'subdir'))
|
| + self.assertEqual(c.ClassifyFile('#/src/tools/build/t.c'), ('source', 'C'))
|
| +
|
| + def testGetCoveredFile(self):
|
| + """Test GetCoveredFile()."""
|
| + c = self.cov_minimal
|
| +
|
| + # Not currently any covered files
|
| + self.assertEqual(c.GetCoveredFile('#/a.c'), None)
|
| +
|
| + # Add some files
|
| + a_c = c.GetCoveredFile('#/a.c', add=True)
|
| + b_c = c.GetCoveredFile('#/b.c##', add=True)
|
| + self.assertEqual(a_c.filename, '#/a.c')
|
| + self.assertEqual(a_c.group, 'my')
|
| + self.assertEqual(a_c.language, 'C')
|
| + self.assertEqual(b_c.filename, '#/b.c##')
|
| + self.assertEqual(b_c.group, 'my')
|
| + self.assertEqual(b_c.language, 'C##')
|
| +
|
| + # Specifying the same filename should return the existing object
|
| + self.assertEqual(c.GetCoveredFile('#/a.c'), a_c)
|
| + self.assertEqual(c.GetCoveredFile('#/a.c', add=True), a_c)
|
| +
|
| + # Filenames get cleaned on the way in, as do root paths
|
| + self.assertEqual(c.GetCoveredFile('/src/a.c'), a_c)
|
| + self.assertEqual(c.GetCoveredFile('c:\\source\\a.c'), a_c)
|
| +
|
| + def testParseLcov(self):
|
| + """Test ParseLcovData()."""
|
| + c = self.cov_minimal
|
| +
|
| + c.ParseLcovData([
|
| + '# Ignore unknown lines',
|
| + # File we should include'
|
| + 'SF:/src/a.c',
|
| + 'DA:10,1',
|
| + 'DA:11,0',
|
| + 'DA:12,1 \n', # Trailing whitespace should get stripped
|
| + 'end_of_record',
|
| + # File we should ignore
|
| + 'SF:/not_src/a.c',
|
| + 'DA:20,1',
|
| + 'end_of_record',
|
| + # Same as first source file, but alternate root
|
| + 'SF:c:\\source\\a.c',
|
| + 'DA:30,1',
|
| + 'end_of_record',
|
| + # Ignore extra end of record
|
| + 'end_of_record',
|
| + # Ignore data points after end of record
|
| + 'DA:40,1',
|
| + # Instrumented but uncovered file
|
| + 'SF:/src/b.c',
|
| + 'DA:50,0',
|
| + 'end_of_record',
|
| + ])
|
| +
|
| + # We should know about two files
|
| + self.assertEqual(sorted(c.files), ['#/a.c', '#/b.c'])
|
| +
|
| + # Check expected contents
|
| + a_c = c.GetCoveredFile('#/a.c')
|
| + self.assertEqual(a_c.lines, {10: 1, 11: 0, 12: 1, 30: 1})
|
| + self.assertEqual(a_c.stats, {
|
| + 'files_executable': 1,
|
| + 'files_instrumented': 1,
|
| + 'files_covered': 1,
|
| + 'lines_instrumented': 4,
|
| + 'lines_executable': 4,
|
| + 'lines_covered': 3,
|
| + })
|
| + b_c = c.GetCoveredFile('#/b.c')
|
| + self.assertEqual(b_c.lines, {50: 0})
|
| + self.assertEqual(b_c.stats, {
|
| + 'files_executable': 1,
|
| + 'files_instrumented': 1,
|
| + 'lines_instrumented': 1,
|
| + 'lines_executable': 1,
|
| + 'lines_covered': 0,
|
| + })
|
| +
|
| + def testGetStat(self):
|
| + """Test GetStat() and PrintStat()."""
|
| + c = self.cov
|
| +
|
| + # Add some stats, so there's something to report
|
| + c.tree.stats_by_group = {
|
| + 'all': {
|
| + 'count_a': 10,
|
| + 'count_b': 4,
|
| + 'foo': 'bar',
|
| + },
|
| + 'tests': {
|
| + 'count_a': 2,
|
| + 'count_b': 5,
|
| + 'baz': 'bob',
|
| + },
|
| + }
|
| +
|
| + # Test missing stats and groups
|
| + self.assertRaises(croc.CoverageStatError, c.GetStat, 'nosuch')
|
| + self.assertRaises(croc.CoverageStatError, c.GetStat, 'baz')
|
| + self.assertRaises(croc.CoverageStatError, c.GetStat, 'foo', group='tests')
|
| + self.assertRaises(croc.CoverageStatError, c.GetStat, 'foo', group='nosuch')
|
| +
|
| + # Test returning defaults
|
| + self.assertEqual(c.GetStat('nosuch', default=13), 13)
|
| + self.assertEqual(c.GetStat('baz', default='aaa'), 'aaa')
|
| + self.assertEqual(c.GetStat('foo', group='tests', default=0), 0)
|
| + self.assertEqual(c.GetStat('foo', group='nosuch', default=''), '')
|
| +
|
| + # Test getting stats
|
| + self.assertEqual(c.GetStat('count_a'), 10)
|
| + self.assertEqual(c.GetStat('count_a', group='tests'), 2)
|
| + self.assertEqual(c.GetStat('foo', default='baz'), 'bar')
|
| +
|
| + # Test stat math (eval)
|
| + self.assertEqual(c.GetStat('count_a - count_b'), 6)
|
| + self.assertEqual(c.GetStat('100.0 * count_a / count_b', group='tests'),
|
| + 40.0)
|
| + # Should catch eval errors
|
| + self.assertRaises(croc.CoverageStatError, c.GetStat, '100 / 0')
|
| + self.assertRaises(croc.CoverageStatError, c.GetStat, 'count_a -')
|
| +
|
| + # Test nested stats via S()
|
| + self.assertEqual(c.GetStat('count_a - S("count_a", group="tests")'), 8)
|
| + self.assertRaises(croc.CoverageStatError, c.GetStat, 'S()')
|
| + self.assertRaises(croc.CoverageStatError, c.GetStat, 'S("nosuch")')
|
| +
|
| + # Test PrintStat()
|
| + # We won't see the first print, but at least verify it doesn't assert
|
| + c.PrintStat('count_a', format='(test to stdout: %s)')
|
| + # Send subsequent prints to a file
|
| + f = StringIO.StringIO()
|
| + c.PrintStat('count_b', outfile=f)
|
| + # Test specifying output format
|
| + c.PrintStat('count_a', format='Count A = %05d', outfile=f)
|
| + # Test specifing additional keyword args
|
| + c.PrintStat('count_a', group='tests', outfile=f)
|
| + c.PrintStat('nosuch', default=42, outfile=f)
|
| + self.assertEqual(f.getvalue(), ("""\
|
| +GetStat('count_b') = 4
|
| +Count A = 00010
|
| +GetStat('count_a') = 2
|
| +GetStat('nosuch') = 42
|
| +"""))
|
| + f.close()
|
| +
|
| + def testAddConfigEmpty(self):
|
| + """Test AddConfig() with empty config."""
|
| + c = self.cov
|
| + # Most minimal config is an empty dict; should do nothing
|
| + c.AddConfig('{} # And we ignore comments')
|
| +
|
| + def testAddConfig(self):
|
| + """Test AddConfig()."""
|
| + c = self.cov
|
| + lcov_queue = []
|
| + addfiles_queue = []
|
| +
|
| + c.AddConfig("""{
|
| + 'roots' : [
|
| + {'root' : '/foo'},
|
| + {'root' : '/bar', 'altname' : '#BAR'},
|
| + ],
|
| + 'rules' : [
|
| + {'regexp' : '^#', 'group' : 'apple'},
|
| + {'regexp' : 're2', 'include' : 1, 'language' : 'elvish'},
|
| + ],
|
| + 'lcov_files' : ['a.lcov', 'b.lcov'],
|
| + 'add_files' : ['/src', '#BAR/doo'],
|
| + 'print_stats' : [
|
| + {'stat' : 'count_a'},
|
| + {'stat' : 'count_b', 'group' : 'tests'},
|
| + ],
|
| + 'extra_key' : 'is ignored',
|
| + }""", lcov_queue=lcov_queue, addfiles_queue=addfiles_queue)
|
| +
|
| + self.assertEqual(lcov_queue, ['a.lcov', 'b.lcov'])
|
| + self.assertEqual(addfiles_queue, ['/src', '#BAR/doo'])
|
| + self.assertEqual(c.root_dirs, [['/foo', '#'], ['/bar', '#BAR']])
|
| + self.assertEqual(c.print_stats, [
|
| + {'stat': 'count_a'},
|
| + {'stat': 'count_b', 'group': 'tests'},
|
| + ])
|
| + # Convert compiled re's back to patterns for comparison
|
| + rules = [[r[0].pattern] + r[1:] for r in c.rules]
|
| + self.assertEqual(rules, [
|
| + ['.*/$', None, None, 'subdir'],
|
| + ['^#', None, 'apple', None],
|
| + ['re2', 1, None, 'elvish'],
|
| + ])
|
| +
|
| + def testAddFilesSimple(self):
|
| + """Test AddFiles() simple call."""
|
| + c = self.cov_minimal
|
| + c.add_files_walk = self.MockWalk
|
| + c.AddFiles('/a/b/c')
|
| + self.assertEqual(self.mock_walk_calls, ['/a/b/c'])
|
| + self.assertEqual(c.files, {})
|
| +
|
| + def testAddFilesRootMap(self):
|
| + """Test AddFiles() with root mappings."""
|
| + c = self.cov_minimal
|
| + c.add_files_walk = self.MockWalk
|
| + c.AddRoot('#/subdir', '#SUBDIR')
|
| +
|
| + # AddFiles() should replace the '#SUBDIR' alt_name, then match both
|
| + # possible roots for the '#' alt_name.
|
| + c.AddFiles('#SUBDIR/foo')
|
| + self.assertEqual(self.mock_walk_calls,
|
| + ['/src/subdir/foo', 'c:/source/subdir/foo'])
|
| + self.assertEqual(c.files, {})
|
| +
|
| + def testAddFilesNonEmpty(self):
|
| + """Test AddFiles() where files are returned."""
|
| +
|
| + c = self.cov_minimal
|
| + c.add_files_walk = self.MockWalk
|
| +
|
| + # Add a rule to exclude a subdir
|
| + c.AddRule('^#/proj1/excluded/', include=0)
|
| +
|
| + # Set data for mock walk
|
| + self.mock_walk_return = [
|
| + [
|
| + '/src/proj1',
|
| + ['excluded', 'subdir'],
|
| + ['a.c', 'no.f', 'yes.c'],
|
| + ],
|
| + [
|
| + '/src/proj1/subdir',
|
| + [],
|
| + ['cherry.c'],
|
| + ],
|
| + ]
|
| +
|
| + c.AddFiles('/src/proj1')
|
| +
|
| + self.assertEqual(self.mock_walk_calls, ['/src/proj1'])
|
| +
|
| + # Include files from the main dir and subdir
|
| + self.assertEqual(sorted(c.files), [
|
| + '#/proj1/a.c',
|
| + '#/proj1/subdir/cherry.c',
|
| + '#/proj1/yes.c'])
|
| +
|
| + # Excluded dir should have been pruned from the mock walk data dirnames.
|
| + # In the real os.walk() call this prunes the walk.
|
| + self.assertEqual(self.mock_walk_return[0][1], ['subdir'])
|
| +
|
| + def testUpdateTreeStats(self):
|
| + """Test UpdateTreeStats()."""
|
| +
|
| + c = self.cov_minimal
|
| +
|
| +
|
| +
|
| + c.AddRule('.*_test', group='test')
|
| +
|
| + # Fill the files list
|
| + c.ParseLcovData([
|
| + 'SF:/src/a.c',
|
| + 'DA:10,1', 'DA:11,1', 'DA:20,0',
|
| + 'end_of_record',
|
| + 'SF:/src/a_test.c',
|
| + 'DA:10,1', 'DA:11,1', 'DA:12,1',
|
| + 'end_of_record',
|
| + 'SF:/src/foo/b.c',
|
| + 'DA:10,1', 'DA:11,1', 'DA:20,0', 'DA:21,0', 'DA:30,0',
|
| + 'end_of_record',
|
| + 'SF:/src/foo/b_test.c',
|
| + 'DA:20,0', 'DA:21,0', 'DA:22,0',
|
| + 'end_of_record',
|
| + ])
|
| + c.UpdateTreeStats()
|
| +
|
| + t = c.tree
|
| + self.assertEqual(t.dirpath, '')
|
| + self.assertEqual(sorted(t.files), [])
|
| + self.assertEqual(sorted(t.subdirs), ['#'])
|
| + self.assertEqual(t.stats_by_group, {
|
| + 'all': {
|
| + 'files_covered': 3,
|
| + 'files_executable': 4,
|
| + 'lines_executable': 14,
|
| + 'lines_covered': 7,
|
| + 'lines_instrumented': 14,
|
| + 'files_instrumented': 4,
|
| + },
|
| + 'my': {
|
| + 'files_covered': 2,
|
| + 'files_executable': 2,
|
| + 'lines_executable': 8,
|
| + 'lines_covered': 4,
|
| + 'lines_instrumented': 8,
|
| + 'files_instrumented': 2,
|
| + },
|
| + 'test': {
|
| + 'files_covered': 1,
|
| + 'files_executable': 2,
|
| + 'lines_executable': 6,
|
| + 'lines_covered': 3,
|
| + 'lines_instrumented': 6,
|
| + 'files_instrumented': 2,
|
| + },
|
| + })
|
| +
|
| + t = t.subdirs['#']
|
| + self.assertEqual(t.dirpath, '#')
|
| + self.assertEqual(sorted(t.files), ['a.c', 'a_test.c'])
|
| + self.assertEqual(sorted(t.subdirs), ['foo'])
|
| + self.assertEqual(t.stats_by_group, {
|
| + 'all': {
|
| + 'files_covered': 3,
|
| + 'files_executable': 4,
|
| + 'lines_executable': 14,
|
| + 'lines_covered': 7,
|
| + 'lines_instrumented': 14,
|
| + 'files_instrumented': 4,
|
| + },
|
| + 'my': {
|
| + 'files_covered': 2,
|
| + 'files_executable': 2,
|
| + 'lines_executable': 8,
|
| + 'lines_covered': 4,
|
| + 'lines_instrumented': 8,
|
| + 'files_instrumented': 2,
|
| + },
|
| + 'test': {
|
| + 'files_covered': 1,
|
| + 'files_executable': 2,
|
| + 'lines_executable': 6,
|
| + 'lines_covered': 3,
|
| + 'lines_instrumented': 6,
|
| + 'files_instrumented': 2,
|
| + },
|
| + })
|
| +
|
| + t = t.subdirs['foo']
|
| + self.assertEqual(t.dirpath, 'foo')
|
| + self.assertEqual(sorted(t.files), ['b.c', 'b_test.c'])
|
| + self.assertEqual(sorted(t.subdirs), [])
|
| + self.assertEqual(t.stats_by_group, {
|
| + 'test': {
|
| + 'files_executable': 1,
|
| + 'files_instrumented': 1,
|
| + 'lines_executable': 3,
|
| + 'lines_instrumented': 3,
|
| + 'lines_covered': 0,
|
| + },
|
| + 'all': {
|
| + 'files_covered': 1,
|
| + 'files_executable': 2,
|
| + 'lines_executable': 8,
|
| + 'lines_covered': 2,
|
| + 'lines_instrumented': 8,
|
| + 'files_instrumented': 2,
|
| + },
|
| + 'my': {
|
| + 'files_covered': 1,
|
| + 'files_executable': 1,
|
| + 'lines_executable': 5,
|
| + 'lines_covered': 2,
|
| + 'lines_instrumented': 5,
|
| + 'files_instrumented': 1,
|
| + }
|
| + })
|
| +
|
| + # TODO: test: less important, since these are thin wrappers around other
|
| + # tested methods.
|
| + # ParseConfig()
|
| + # ParseLcovFile()
|
| + # PrintTree()
|
| +
|
| +#------------------------------------------------------------------------------
|
| +
|
| +if __name__ == '__main__':
|
| + unittest.main()
|
|
|