#!/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()