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