#!/usr/bin/env python3
# Copyright 2018 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Tests for extract_sqlite_api.py.
These tests should be getting picked up by the PRESUBMIT.py in this directory.
"""
from importlib.machinery import SourceFileLoader
import os
import shutil
import sys
import tempfile
import unittest
class ExtractSqliteApiUnittest(unittest.TestCase):
def setUp(self):
self.test_root = tempfile.mkdtemp()
source_path = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
'extract_sqlite_api.py')
self.extractor = SourceFileLoader('extract_api',
source_path).load_module()
def tearDown(self):
if self.test_root:
shutil.rmtree(self.test_root)
def testExtractLineTuples(self):
golden = [(1, 'Line1'), (2, ''), (3, 'Line 2'), (4, 'Line3'), (5, '')]
text_with_newline = "Line1\n\nLine 2 \nLine3\n"
self.assertEqual(
self.extractor.ExtractLineTuples(text_with_newline), golden)
golden = [(1, 'Line1'), (2, ''), (3, 'Line 2'), (4, 'Line3')]
text_without_newline = "Line1\n\nLine 2 \nLine3"
self.assertEqual(
self.extractor.ExtractLineTuples(text_without_newline), golden)
def testExtractPreprocessorDirectives(self):
lines = [
(1, '// Header comment'),
(2, '#define DIRECTIVE 1'),
(3, 'int main() { // \\'),
(4, '}'),
(5, ''),
(6, '#define MULTILINE \\'),
(7, 'MORE_MULTILINE_DIRECTIVE\\'),
(8, 'END_MULTILINE_DIRECTIVE'),
(9, 'void code() { }'),
]
directives, code_lines = self.extractor.ExtractPreprocessorDirectives(
lines)
self.assertEqual(directives, [
'#define DIRECTIVE 1',
'#define MULTILINE \nMORE_MULTILINE_DIRECTIVE\nEND_MULTILINE_DIRECTIVE',
])
self.assertEqual(code_lines, [
(1, '// Header comment'),
(3, 'int main() { // \\'),
(4, '}'),
(5, ''),
(9, 'void code() { }'),
])
def testExtractDefineMacroName(self):
self.assertEqual(
'SQLITE_API',
self.extractor.ExtractDefineMacroName('#define SQLITE_API 1'))
self.assertEqual(
'SQLITE_API',
self.extractor.ExtractDefineMacroName('#define SQLITE_API'))
self.assertEqual(
'SQLITE_API',
self.extractor.ExtractDefineMacroName('#define SQLITE_API\n1'))
self.assertEqual(
'SQLITE_API',
self.extractor.ExtractDefineMacroName(
'# define SQLITE_API 1'))
self.assertEqual(
'SQLITE_API',
self.extractor.ExtractDefineMacroName('#\tdefine\tSQLITE_API\t1'))
self.assertEqual(
None,
self.extractor.ExtractDefineMacroName(' #define SQLITE_API 1'))
self.assertEqual(
None,
self.extractor.ExtractDefineMacroName(' #define SQLITE_API() 1'))
self.assertEqual(None, self.extractor.ExtractDefineMacroName(''))
def testRemoveLineComments(self):
self.assertEqual('word;', self.extractor.RemoveLineComments('word;'))
self.assertEqual('', self.extractor.RemoveLineComments(''))
self.assertEqual('', self.extractor.RemoveLineComments('// comment'))
self.assertEqual('',
self.extractor.RemoveLineComments('/* comment */'))
self.assertEqual('word;',
self.extractor.RemoveLineComments('wo/*comment*/rd;'))
self.assertEqual(
'word;*/', self.extractor.RemoveLineComments('wo/*comment*/rd;*/'))
self.assertEqual(
'word;*/',
self.extractor.RemoveLineComments('wo/*/*comment*/rd;*/'))
self.assertEqual(
'word;', self.extractor.RemoveLineComments('wo/*comm//ent*/rd;'))
def testRemoveComments(self):
lines = [
(1, 'code();'),
(2, 'more_code(); /* with comment */ more_code();'),
(3, '/**'),
(4, 'Spec text'),
(5, '**/ spec_code();'),
(6,
'late_code(); /* with comment */ more_late_code(); /* late comment'
),
(7, 'ends here // C++ trap */ code(); // /* C trap'),
(8, 'last_code();'),
]
self.assertEqual(
self.extractor.RemoveComments(lines), [
(1, 'code();'),
(2, 'more_code(); more_code();'),
(3, ''),
(5, ' spec_code();'),
(6, 'late_code(); more_late_code(); '),
(7, ' code(); '),
(8, 'last_code();'),
])
def testToStatementTuples(self):
lines = [(1, 'void function();'), (2, 'int main('),
(3, ' int argc, char* argv) {'),
(4, ' statement1; statement2;'), (5, '}'), (6, 'stat'),
(7, 'ement4; statement5; sta'), (8, 'tem'),
(9, 'ent6; statement7;')]
self.assertEqual(
self.extractor.ToStatementTuples(lines), [
(1, 1, 'void function()'),
(2, 3, 'int main(\n int argc, char* argv)'),
(4, 4, 'statement1'),
(4, 4, 'statement2'),
(5, 5, ''),
(6, 7, 'stat\nement4'),
(7, 7, 'statement5'),
(7, 9, 'sta\ntem\nent6'),
(9, 9, 'statement7'),
])
def testExtractApiExport(self):
self.assertEqual(
'sqlite3_init',
self.extractor.ExtractApiExport(set(), 'SQLITE_API',
'SQLITE_API void sqlite3_init()'))
self.assertEqual(
'sqlite3_sleep',
self.extractor.ExtractApiExport(
set(), 'SQLITE_API', 'SQLITE_API int sqlite3_sleep(int ms)'))
self.assertEqual(
'sqlite3_sleep',
self.extractor.ExtractApiExport(
set(), 'SQLITE_API',
'SQLITE_API long long sqlite3_sleep(int ms)'))
self.assertEqual(
'sqlite3rbu_temp_size',
self.extractor.ExtractApiExport(
set(), 'SQLITE_API',
'SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu)'
))
self.assertEqual(
'sqlite3_expired',
self.extractor.ExtractApiExport(
set(['SQLITE_DEPRECATED']), 'SQLITE_API',
'SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*)'
))
# SQLite's header actually #defines double (in some cases).
self.assertEqual(
'sqlite3_column_double',
self.extractor.ExtractApiExport(
set(['double']), 'SQLITE_API',
'SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol)'
))
self.assertEqual(
'sqlite3_temp_directory',
self.extractor.ExtractApiExport(
set(['SQLITE_EXTERN']), 'SQLITE_API',
'SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory'))
self.assertEqual(
'sqlite3_version',
self.extractor.ExtractApiExport(
set(['SQLITE_EXTERN']), 'SQLITE_API',
'SQLITE_API SQLITE_EXTERN const char sqlite3_version[]'))
self.assertEqual(
None,
self.extractor.ExtractApiExport(
set(['SQLITE_DEPRECATED']), 'SQLITE_API',
'NOT_SQLITE_API struct sqlite_type sqlite3_sleep(int ms)'))
with self.assertRaisesRegex(self.extractor.ExtractError,
'Mixed simple .* and composite'):
self.extractor.ExtractApiExport(
set(), 'SQLITE_API',
'SQLITE_API void int sqlite3_sleep(int ms)')
with self.assertRaisesRegex(self.extractor.ExtractError,
'Unsupported keyword struct'):
self.extractor.ExtractApiExport(
set(), 'SQLITE_API',
'SQLITE_API struct sqlite_type sqlite3_sleep(int ms)')
with self.assertRaisesRegex(self.extractor.ExtractError,
'int\+\+ parsed as type name'):
self.extractor.ExtractApiExport(
set(), 'SQLITE_API', 'SQLITE_API int++ sqlite3_sleep(int ms)')
with self.assertRaisesRegex(self.extractor.ExtractError,
'sqlite3\+sleep parsed as symbol'):
self.extractor.ExtractApiExport(
set(), 'SQLITE_API', 'SQLITE_API int sqlite3+sleep(int ms)')
def testExportedSymbolLine(self):
self.assertEqual(
'#define sqlite3_sleep chrome_sqlite3_sleep // Line 42',
self.extractor.ExportedSymbolLine(
'chrome_', 'sqlite3_sleep',
(42, 42, 'SQLITE_API int chrome_sqlite3_sleep(int ms)')))
self.assertEqual(
'#define sqlite3_sleep chrome_sqlite3_sleep // Lines 42-44',
self.extractor.ExportedSymbolLine(
'chrome_', 'sqlite3_sleep',
(42, 44, 'SQLITE_API int chrome_sqlite3_sleep(int ms)')))
def testExportedExceptionLine(self):
self.assertEqual(
'// TODO: Lines 42-44 -- Something went wrong',
self.extractor.ExportedExceptionLine(
self.extractor.ExtractError('Something went wrong'),
(42, 44, 'SQLITE_API int chrome_sqlite3_sleep(int ms)')))
def testProcessSource(self):
file_content = '\n'.join([
'/*',
'struct sqlite_type sqlite3_sleep; // Remove comments',
'*/',
'#define SQLITE_DEPRECATED',
'SQLITE_API int sqlite3_sleep(int ms);',
'SQLITE_API struct sqlite_type sqlite3_sleep(int ms);',
'SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);',
])
golden_output = [
'// Header',
'#define sqlite3_expired chrome_sqlite3_expired // Line 7',
'#define sqlite3_sleep chrome_sqlite3_sleep // Line 5',
'// TODO: Lines 6-6 -- Unsupported keyword struct',
'// Footer',
]
self.assertEqual(
golden_output,
self.extractor.ProcessSource('SQLITE_API', 'chrome_', '// Header',
'// Footer', file_content))
def testProcessSourceFile(self):
file_content = '\n'.join([
'/*',
'struct sqlite_type sqlite3_sleep; // Remove comments',
'*/',
'#define SQLITE_DEPRECATED',
'SQLITE_API int sqlite3_sleep(int ms);',
'SQLITE_API struct sqlite_type sqlite3_sleep(int ms);',
'SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);',
])
golden_output = '\n'.join([
'// Header',
'#define sqlite3_expired chrome_sqlite3_expired // Line 7',
'#define sqlite3_sleep chrome_sqlite3_sleep // Line 5',
'// TODO: Lines 6-6 -- Unsupported keyword struct',
'// Footer',
'',
])
input_file = os.path.join(self.test_root, 'input.h')
output_file = os.path.join(self.test_root, 'macros.h')
with open(input_file, 'w') as f:
f.write(file_content)
self.extractor.ProcessSourceFile('SQLITE_API', 'chrome_', '// Header',
'// Footer', input_file, output_file)
with open(output_file, 'r') as f:
self.assertEqual(f.read(), golden_output)
if __name__ == '__main__':
unittest.main()