1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
#!/usr/bin/env python
# Copyright 2017 The PDFium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Verifies exported functions in public/*.h are in fpdfview_c_api_test.c.
This script gathers a list of functions from public/*.h that contain
FPDF_EXPORT. It then gathers a list of functions from
fpdfsdk/fpdfview_c_api_test.c. It then verifies both lists do not contain
duplicates, and they match each other.
"""
import os
import re
import sys
def _IsValidFunctionName(function, filename):
if function.startswith('FPDF'):
return True
if function == 'FSDK_SetUnSpObjProcessHandler' and filename == 'fpdf_ext.h':
return True
if function.startswith('FORM_') and filename == 'fpdf_formfill.h':
return True
return False
def _FindFunction(function_snippet, filename):
function_split = function_snippet.split('(')
assert len(function_split) == 2
function = function_split[0]
assert _IsValidFunctionName(function, filename)
return function
def _GetExportsFromHeader(dirname, filename):
with open(os.path.join(dirname, filename)) as f:
contents = f.readlines()
look_for_function_name = False
functions = []
for line in contents:
if look_for_function_name:
look_for_function_name = False
split_line = line.rstrip().split(' ')
functions.append(_FindFunction(split_line[0], filename))
continue
if not line.startswith('FPDF_EXPORT '):
continue
# Format should be: FPDF_EXPORT return_type FPDF_CALLCONV
split_line = line.rstrip().split(' ')
callconv_index = split_line.index('FPDF_CALLCONV')
assert callconv_index >= 2
if callconv_index + 1 == len(split_line):
look_for_function_name = True
continue
functions.append(_FindFunction(split_line[callconv_index + 1], filename))
return functions
def _GetFunctionsFromPublicHeaders(src_path):
public_path = os.path.join(src_path, 'public')
functions = []
for filename in os.listdir(public_path):
if filename.endswith('.h'):
functions.extend(_GetExportsFromHeader(public_path, filename))
return functions
def _GetFunctionsFromTest(api_test_path):
chk_regex = re.compile('^ CHK\((.*)\);\n$')
with open(api_test_path) as f:
contents = f.readlines()
functions = []
for line in contents:
match = chk_regex.match(line)
if match:
functions.append(match.groups()[0])
return functions
def _FindDuplicates(functions):
return set([f for f in functions if functions.count(f) > 1])
def _CheckAndPrintFailures(failure_list, failure_message):
if not failure_list:
return True
print '%s:' % failure_message
for f in sorted(failure_list):
print f
return False
def main():
script_abspath = os.path.abspath(__file__)
src_path = os.path.dirname(os.path.dirname(os.path.dirname(script_abspath)))
public_functions = _GetFunctionsFromPublicHeaders(src_path)
api_test_relative_path = os.path.join('fpdfsdk', 'fpdfview_c_api_test.c')
api_test_path = os.path.join(src_path, api_test_relative_path)
test_functions = _GetFunctionsFromTest(api_test_path)
result = True
duplicate_public_functions = _FindDuplicates(public_functions)
check = _CheckAndPrintFailures(duplicate_public_functions,
'Found duplicate functions in public headers')
result = result and check
duplicate_test_functions = _FindDuplicates(test_functions)
check = _CheckAndPrintFailures(duplicate_test_functions,
'Found duplicate functions in API test')
result = result and check
public_functions_set = set(public_functions)
test_functions_set = set(test_functions)
not_tested = public_functions_set.difference(test_functions_set)
check = _CheckAndPrintFailures(not_tested, 'Functions not tested')
result = result and check
non_existent = test_functions_set.difference(public_functions_set)
check = _CheckAndPrintFailures(non_existent, 'Tested functions do not exist')
result = result and check
if not result:
print ('Some checks failed. Make sure %s is in sync with the public API '
'headers.'
% api_test_relative_path);
return 1
return 0
if __name__ == '__main__':
sys.exit(main())
|