188 lines
7.0 KiB
Python
188 lines
7.0 KiB
Python
|
#!/usr/bin/env python
|
||
|
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||
|
# Use of this source code is governed by a BSD-style license that can be
|
||
|
# found in the LICENSE file.
|
||
|
|
||
|
"""Unit tests for croc_scan.py."""
|
||
|
|
||
|
import re
|
||
|
import unittest
|
||
|
import croc_scan
|
||
|
|
||
|
|
||
|
class TestScanner(unittest.TestCase):
|
||
|
"""Tests for croc_scan.Scanner."""
|
||
|
|
||
|
def testInit(self):
|
||
|
"""Test __init()__."""
|
||
|
s = croc_scan.Scanner()
|
||
|
|
||
|
self.assertEqual(s.re_token.pattern, '#')
|
||
|
self.assertEqual(s.comment_to_eol, ['#'])
|
||
|
self.assertEqual(s.comment_start, None)
|
||
|
self.assertEqual(s.comment_end, None)
|
||
|
|
||
|
def testScanLines(self):
|
||
|
"""Test ScanLines()."""
|
||
|
s = croc_scan.Scanner()
|
||
|
# Set up imaginary language:
|
||
|
# ':' = comment to EOL
|
||
|
# '"' = string start/end
|
||
|
# '(' = comment start
|
||
|
# ')' = comment end
|
||
|
s.re_token = re.compile(r'([\:\"\(\)])')
|
||
|
s.comment_to_eol = [':']
|
||
|
s.comment_start = '('
|
||
|
s.comment_end = ')'
|
||
|
|
||
|
# No input file = no output lines
|
||
|
self.assertEqual(s.ScanLines([]), [])
|
||
|
|
||
|
# Empty lines and lines with only whitespace are ignored
|
||
|
self.assertEqual(s.ScanLines([
|
||
|
'', # 1
|
||
|
'line', # 2 exe
|
||
|
' \t ', # 3
|
||
|
]), [2])
|
||
|
|
||
|
# Comments to EOL are stripped, but not inside strings
|
||
|
self.assertEqual(s.ScanLines([
|
||
|
'test', # 1 exe
|
||
|
' : A comment', # 2
|
||
|
'"a : in a string"', # 3 exe
|
||
|
'test2 : with comment to EOL', # 4 exe
|
||
|
'foo = "a multiline string with an empty line', # 5 exe
|
||
|
'', # 6 exe
|
||
|
': and a comment-to-EOL character"', # 7 exe
|
||
|
': done', # 8
|
||
|
]), [1, 3, 4, 5, 6, 7])
|
||
|
|
||
|
# Test Comment start/stop detection
|
||
|
self.assertEqual(s.ScanLines([
|
||
|
'( a comment on one line)', # 1
|
||
|
'text (with a comment)', # 2 exe
|
||
|
'( a comment with a : in the middle)', # 3
|
||
|
'( a multi-line', # 4
|
||
|
' comment)', # 5
|
||
|
'a string "with a ( in it"', # 6 exe
|
||
|
'not in a multi-line comment', # 7 exe
|
||
|
'(a comment with a " in it)', # 8
|
||
|
': not in a string, so this gets stripped', # 9
|
||
|
'more text "with an uninteresting string"', # 10 exe
|
||
|
]), [2, 6, 7, 10])
|
||
|
|
||
|
# TODO: Test Scan(). Low priority, since it just wraps ScanLines().
|
||
|
|
||
|
|
||
|
class TestPythonScanner(unittest.TestCase):
|
||
|
"""Tests for croc_scan.PythonScanner."""
|
||
|
|
||
|
def testScanLines(self):
|
||
|
"""Test ScanLines()."""
|
||
|
s = croc_scan.PythonScanner()
|
||
|
|
||
|
# No input file = no output lines
|
||
|
self.assertEqual(s.ScanLines([]), [])
|
||
|
|
||
|
self.assertEqual(s.ScanLines([
|
||
|
'# a comment', # 1
|
||
|
'', # 2
|
||
|
'"""multi-line string', # 3 exe
|
||
|
'# not a comment', # 4 exe
|
||
|
'end of multi-line string"""', # 5 exe
|
||
|
' ', # 6
|
||
|
'"single string with #comment"', # 7 exe
|
||
|
'', # 8
|
||
|
'\'\'\'multi-line string, single-quote', # 9 exe
|
||
|
'# not a comment', # 10 exe
|
||
|
'end of multi-line string\'\'\'', # 11 exe
|
||
|
'', # 12
|
||
|
'"string with embedded \\" is handled"', # 13 exe
|
||
|
'# quoted "', # 14
|
||
|
'"\\""', # 15 exe
|
||
|
'# quoted backslash', # 16
|
||
|
'"\\\\"', # 17 exe
|
||
|
'main()', # 18 exe
|
||
|
'# end', # 19
|
||
|
]), [3, 4, 5, 7, 9, 10, 11, 13, 15, 17, 18])
|
||
|
|
||
|
|
||
|
class TestCppScanner(unittest.TestCase):
|
||
|
"""Tests for croc_scan.CppScanner."""
|
||
|
|
||
|
def testScanLines(self):
|
||
|
"""Test ScanLines()."""
|
||
|
s = croc_scan.CppScanner()
|
||
|
|
||
|
# No input file = no output lines
|
||
|
self.assertEqual(s.ScanLines([]), [])
|
||
|
|
||
|
self.assertEqual(s.ScanLines([
|
||
|
'// a comment', # 1
|
||
|
'# a preprocessor define', # 2
|
||
|
'', # 3
|
||
|
'\'#\', \'"\'', # 4 exe
|
||
|
'', # 5
|
||
|
'/* a multi-line comment', # 6
|
||
|
'with a " in it', # 7
|
||
|
'*/', # 8
|
||
|
'', # 9
|
||
|
'"a string with /* and \' in it"', # 10 exe
|
||
|
'', # 11
|
||
|
'"a multi-line string\\', # 12 exe
|
||
|
'// not a comment\\', # 13 exe
|
||
|
'ending here"', # 14 exe
|
||
|
'', # 15
|
||
|
'"string with embedded \\" is handled"', # 16 exe
|
||
|
'', # 17
|
||
|
'main()', # 18 exe
|
||
|
'// end', # 19
|
||
|
]), [4, 10, 12, 13, 14, 16, 18])
|
||
|
|
||
|
|
||
|
class TestScanFile(unittest.TestCase):
|
||
|
"""Tests for croc_scan.ScanFile()."""
|
||
|
|
||
|
class MockScanner(object):
|
||
|
"""Mock scanner."""
|
||
|
|
||
|
def __init__(self, language):
|
||
|
"""Constructor."""
|
||
|
self.language = language
|
||
|
|
||
|
def Scan(self, filename):
|
||
|
"""Mock Scan() method."""
|
||
|
return 'scan %s %s' % (self.language, filename)
|
||
|
|
||
|
def MockPythonScanner(self):
|
||
|
return self.MockScanner('py')
|
||
|
|
||
|
def MockCppScanner(self):
|
||
|
return self.MockScanner('cpp')
|
||
|
|
||
|
def setUp(self):
|
||
|
"""Per-test setup."""
|
||
|
# Hook scanners
|
||
|
self.old_python_scanner = croc_scan.PythonScanner
|
||
|
self.old_cpp_scanner = croc_scan.CppScanner
|
||
|
croc_scan.PythonScanner = self.MockPythonScanner
|
||
|
croc_scan.CppScanner = self.MockCppScanner
|
||
|
|
||
|
def tearDown(self):
|
||
|
"""Per-test cleanup."""
|
||
|
croc_scan.PythonScanner = self.old_python_scanner
|
||
|
croc_scan.CppScanner = self.old_cpp_scanner
|
||
|
|
||
|
def testScanFile(self):
|
||
|
"""Test ScanFile()."""
|
||
|
self.assertEqual(croc_scan.ScanFile('foo', 'python'), 'scan py foo')
|
||
|
self.assertEqual(croc_scan.ScanFile('bar1', 'C'), 'scan cpp bar1')
|
||
|
self.assertEqual(croc_scan.ScanFile('bar2', 'C++'), 'scan cpp bar2')
|
||
|
self.assertEqual(croc_scan.ScanFile('bar3', 'ObjC'), 'scan cpp bar3')
|
||
|
self.assertEqual(croc_scan.ScanFile('bar4', 'ObjC++'), 'scan cpp bar4')
|
||
|
self.assertEqual(croc_scan.ScanFile('bar', 'fortran'), [])
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
unittest.main()
|