Home | History | Annotate | Download | only in code_coverage
      1 #!/usr/bin/env python
      2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 """Unit tests for croc_scan.py."""
      7 
      8 import re
      9 import unittest
     10 import croc_scan
     11 
     12 
     13 class TestScanner(unittest.TestCase):
     14   """Tests for croc_scan.Scanner."""
     15 
     16   def testInit(self):
     17     """Test __init()__."""
     18     s = croc_scan.Scanner()
     19 
     20     self.assertEqual(s.re_token.pattern, '#')
     21     self.assertEqual(s.comment_to_eol, ['#'])
     22     self.assertEqual(s.comment_start, None)
     23     self.assertEqual(s.comment_end, None)
     24 
     25   def testScanLines(self):
     26     """Test ScanLines()."""
     27     s = croc_scan.Scanner()
     28     # Set up imaginary language:
     29     #   ':' = comment to EOL
     30     #   '"' = string start/end
     31     #   '(' = comment start
     32     #   ')' = comment end
     33     s.re_token = re.compile(r'([\:\"\(\)])')
     34     s.comment_to_eol = [':']
     35     s.comment_start = '('
     36     s.comment_end = ')'
     37 
     38     # No input file = no output lines
     39     self.assertEqual(s.ScanLines([]), [])
     40 
     41     # Empty lines and lines with only whitespace are ignored
     42     self.assertEqual(s.ScanLines([
     43         '',             # 1
     44         'line',         # 2 exe
     45         ' \t  ',        # 3
     46     ]), [2])
     47 
     48     # Comments to EOL are stripped, but not inside strings
     49     self.assertEqual(s.ScanLines([
     50         'test',                                                 # 1 exe
     51         '   : A comment',                                       # 2
     52         '"a : in a string"',                                    # 3 exe
     53         'test2 : with comment to EOL',                          # 4 exe
     54         'foo = "a multiline string with an empty line',         # 5 exe
     55         '',                                                     # 6 exe
     56         ': and a comment-to-EOL character"',                    # 7 exe
     57         ': done',                                               # 8
     58     ]), [1, 3, 4, 5, 6, 7])
     59 
     60     # Test Comment start/stop detection
     61     self.assertEqual(s.ScanLines([
     62         '( a comment on one line)',                     # 1
     63         'text (with a comment)',                        # 2 exe
     64         '( a comment with a : in the middle)',          # 3
     65         '( a multi-line',                               # 4
     66         '  comment)',                                   # 5
     67         'a string "with a ( in it"',                    # 6 exe
     68         'not in a multi-line comment',                  # 7 exe
     69         '(a comment with a " in it)',                   # 8
     70         ': not in a string, so this gets stripped',     # 9
     71         'more text "with an uninteresting string"',     # 10 exe
     72     ]), [2, 6, 7, 10])
     73 
     74   # TODO: Test Scan().  Low priority, since it just wraps ScanLines().
     75 
     76 
     77 class TestPythonScanner(unittest.TestCase):
     78   """Tests for croc_scan.PythonScanner."""
     79 
     80   def testScanLines(self):
     81     """Test ScanLines()."""
     82     s = croc_scan.PythonScanner()
     83 
     84     # No input file = no output lines
     85     self.assertEqual(s.ScanLines([]), [])
     86 
     87     self.assertEqual(s.ScanLines([
     88         '# a comment',                                  # 1
     89         '',                                             # 2
     90         '"""multi-line string',                         # 3 exe
     91         '# not a comment',                              # 4 exe
     92         'end of multi-line string"""',                  # 5 exe
     93         '  ',                                           # 6
     94         '"single string with #comment"',                # 7 exe
     95         '',                                             # 8
     96         '\'\'\'multi-line string, single-quote',        # 9 exe
     97         '# not a comment',                              # 10 exe
     98         'end of multi-line string\'\'\'',               # 11 exe
     99         '',                                             # 12
    100         '"string with embedded \\" is handled"',        # 13 exe
    101         '# quoted "',                                   # 14
    102         '"\\""',                                        # 15 exe
    103         '# quoted backslash',                           # 16
    104         '"\\\\"',                                       # 17 exe
    105         'main()',                                       # 18 exe
    106         '# end',                                        # 19
    107     ]), [3, 4, 5, 7, 9, 10, 11, 13, 15, 17, 18])
    108 
    109 
    110 class TestCppScanner(unittest.TestCase):
    111   """Tests for croc_scan.CppScanner."""
    112 
    113   def testScanLines(self):
    114     """Test ScanLines()."""
    115     s = croc_scan.CppScanner()
    116 
    117     # No input file = no output lines
    118     self.assertEqual(s.ScanLines([]), [])
    119 
    120     self.assertEqual(s.ScanLines([
    121         '// a comment',                                 # 1
    122         '# a preprocessor define',                      # 2
    123         '',                                             # 3
    124         '\'#\', \'"\'',                                 # 4 exe
    125         '',                                             # 5
    126         '/* a multi-line comment',                      # 6
    127         'with a " in it',                               # 7
    128         '*/',                                           # 8
    129         '',                                             # 9
    130         '"a string with /* and \' in it"',              # 10 exe
    131         '',                                             # 11
    132         '"a multi-line string\\',                       # 12 exe
    133         '// not a comment\\',                           # 13 exe
    134         'ending here"',                                 # 14 exe
    135         '',                                             # 15
    136         '"string with embedded \\" is handled"',        # 16 exe
    137         '',                                             # 17
    138         'main()',                                       # 18 exe
    139         '// end',                                       # 19
    140     ]), [4, 10, 12, 13, 14, 16, 18])
    141 
    142 
    143 class TestScanFile(unittest.TestCase):
    144   """Tests for croc_scan.ScanFile()."""
    145 
    146   class MockScanner(object):
    147     """Mock scanner."""
    148 
    149     def __init__(self, language):
    150       """Constructor."""
    151       self.language = language
    152 
    153     def Scan(self, filename):
    154       """Mock Scan() method."""
    155       return 'scan %s %s' % (self.language, filename)
    156 
    157   def MockPythonScanner(self):
    158     return self.MockScanner('py')
    159 
    160   def MockCppScanner(self):
    161     return self.MockScanner('cpp')
    162 
    163   def setUp(self):
    164     """Per-test setup."""
    165     # Hook scanners
    166     self.old_python_scanner = croc_scan.PythonScanner
    167     self.old_cpp_scanner = croc_scan.CppScanner
    168     croc_scan.PythonScanner = self.MockPythonScanner
    169     croc_scan.CppScanner = self.MockCppScanner
    170 
    171   def tearDown(self):
    172     """Per-test cleanup."""
    173     croc_scan.PythonScanner = self.old_python_scanner
    174     croc_scan.CppScanner = self.old_cpp_scanner
    175 
    176   def testScanFile(self):
    177     """Test ScanFile()."""
    178     self.assertEqual(croc_scan.ScanFile('foo', 'python'), 'scan py foo')
    179     self.assertEqual(croc_scan.ScanFile('bar1', 'C'), 'scan cpp bar1')
    180     self.assertEqual(croc_scan.ScanFile('bar2', 'C++'), 'scan cpp bar2')
    181     self.assertEqual(croc_scan.ScanFile('bar3', 'ObjC'), 'scan cpp bar3')
    182     self.assertEqual(croc_scan.ScanFile('bar4', 'ObjC++'), 'scan cpp bar4')
    183     self.assertEqual(croc_scan.ScanFile('bar', 'fortran'), [])
    184 
    185 
    186 if __name__ == '__main__':
    187   unittest.main()
    188