Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(237)

Side by Side Diff: components/cronet/tools/api_static_checks_unittest.py

Issue 2544043002: [Cronet] Enforce Cronet API never modified, only grown (Closed)
Patch Set: remove absolute_import Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/cronet/tools/api_static_checks.py ('k') | components/cronet/tools/update_api.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright 2016 The Chromium Authors. All rights reserved. 2 # Copyright 2016 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """api_static_checks_unittest.py - Unittests for api_static_checks.py""" 6 """api_static_checks_unittest.py - Unittests for api_static_checks.py"""
7 7
8 8
9 import contextlib 9 import contextlib
10 from cStringIO import StringIO 10 from cStringIO import StringIO
11 import os 11 import os
12 import shutil 12 import shutil
13 import sys 13 import sys
14 import tempfile 14 import tempfile
15 import unittest 15 import unittest
16 16
17 from tools import api_static_checks 17 REPOSITORY_ROOT = os.path.abspath(os.path.join(
18 os.path.dirname(__file__), '..', '..', '..'))
19
20 sys.path.append(os.path.join(REPOSITORY_ROOT, 'components'))
21 from cronet.tools import api_static_checks
18 22
19 23
20 ERROR_PREFIX = ( 24 ERROR_PREFIX_CHECK_API_CALLS = (
21 """ERROR: Found the following calls from implementation classes through 25 """ERROR: Found the following calls from implementation classes through
22 API classes. These could fail if older API is used that 26 API classes. These could fail if older API is used that
23 does not contain newer methods. Please call through a 27 does not contain newer methods. Please call through a
24 wrapper class from VersionSafeCallbacks. 28 wrapper class from VersionSafeCallbacks.
25 """) 29 """)
26 30
27 31
32 ERROR_PREFIX_UPDATE_API = (
33 """ERROR: This API was modified or removed:
34 """)
35
36
37 ERROR_SUFFIX_UPDATE_API = (
38 """
39
40 Cronet API methods and classes cannot be modified.
41 """)
42
43
44 CHECK_API_VERSION_PREFIX = (
45 """DO NOT EDIT THIS FILE, USE update_api.py TO UPDATE IT
46
47 """)
48
49
50 API_FILENAME = './android/api.txt'
51 API_VERSION_FILENAME = './android/api_version.txt'
52
53
28 @contextlib.contextmanager 54 @contextlib.contextmanager
29 def capture_output(): 55 def capture_output():
30 # A contextmanger that collects the stdout and stderr of wrapped code 56 # A contextmanger that collects the stdout and stderr of wrapped code
31 57
32 oldout,olderr = sys.stdout, sys.stderr 58 oldout,olderr = sys.stdout, sys.stderr
33 try: 59 try:
34 out=[StringIO(), StringIO()] 60 out=[StringIO(), StringIO()]
35 sys.stdout,sys.stderr = out 61 sys.stdout,sys.stderr = out
36 yield out 62 yield out
37 finally: 63 finally:
38 sys.stdout,sys.stderr = oldout, olderr 64 sys.stdout,sys.stderr = oldout, olderr
39 out[0] = out[0].getvalue() 65 out[0] = out[0].getvalue()
40 out[1] = out[1].getvalue() 66 out[1] = out[1].getvalue()
41 67
42 68
43 class ApiStaticCheckUnitTest(unittest.TestCase): 69 class ApiStaticCheckUnitTest(unittest.TestCase):
44 def setUp(self): 70 def setUp(self):
45 self.temp_dir = tempfile.mkdtemp() 71 self.temp_dir = tempfile.mkdtemp()
46 os.chdir(self.temp_dir) 72 os.chdir(self.temp_dir)
73 os.mkdir('android')
74 with open(API_VERSION_FILENAME, 'w') as api_version_file:
75 api_version_file.write('0')
76 with open(API_FILENAME, 'w') as api_file:
77 api_file.write('}\n')
78 shutil.copytree(os.path.dirname(__file__), 'tools')
47 79
48 80
49 def tearDown(self): 81 def tearDown(self):
50 shutil.rmtree(self.temp_dir) 82 shutil.rmtree(self.temp_dir)
51 83
52 84
53 def make_jar(self, java, class_name): 85 def make_jar(self, java, class_name):
54 # Compile |java| wrapped in a class named |class_name| to a jar file and 86 # Compile |java| wrapped in a class named |class_name| to a jar file and
55 # return jar filename. 87 # return jar filename.
56 88
57 java_filename = class_name + '.java' 89 java_filename = class_name + '.java'
58 class_filename = class_name + '.class' 90 class_filenames = class_name + '*.class'
59 jar_filename = class_name + '.jar' 91 jar_filename = class_name + '.jar'
60 92
61 with open(java_filename, 'w') as java_file: 93 with open(java_filename, 'w') as java_file:
62 java_file.write('public class %s {' % class_name) 94 java_file.write('public class %s {' % class_name)
63 java_file.write(java) 95 java_file.write(java)
64 java_file.write('}') 96 java_file.write('}')
65 os.system('javac %s' % java_filename) 97 os.system('javac %s' % java_filename)
66 os.system('jar cf %s %s' % (jar_filename, class_filename)) 98 os.system('jar cf %s %s' % (jar_filename, class_filenames))
67 return jar_filename 99 return jar_filename
68 100
69 101
70 def run_test(self, api_java, impl_java): 102 def run_check_api_calls(self, api_java, impl_java):
71 api_jar = self.make_jar(api_java, 'Api') 103 test = self
72 impl_jar = self.make_jar(impl_java, 'Impl') 104 class MockOpts(object):
105 def __init__(self):
106 self.api_jar = test.make_jar(api_java, 'Api')
107 self.impl_jar = [test.make_jar(impl_java, 'Impl')]
108 opts = MockOpts()
73 with capture_output() as return_output: 109 with capture_output() as return_output:
74 return_code = api_static_checks.main( 110 return_code = api_static_checks.check_api_calls(opts)
75 ['--api_jar', api_jar, '--impl_jar', impl_jar])
76 return [return_code, return_output[0]] 111 return [return_code, return_output[0]]
77 112
78 113
79 def test_success(self): 114 def test_check_api_calls_success(self):
80 # Test simple classes with functions 115 # Test simple classes with functions
81 self.assertEqual(self.run_test('void a(){}', 'void b(){}'), [True, '']) 116 self.assertEqual(self.run_check_api_calls(
117 'void a(){}', 'void b(){}'), [True, ''])
82 # Test simple classes with functions calling themselves 118 # Test simple classes with functions calling themselves
83 self.assertEqual(self.run_test( 119 self.assertEqual(self.run_check_api_calls(
84 'void a(){} void b(){a();}', 'void c(){} void d(){c();}'), [True, '']) 120 'void a(){} void b(){a();}', 'void c(){} void d(){c();}'), [True, ''])
85 121
86 122
87 def test_failure(self): 123 def test_check_api_calls_failure(self):
88 # Test static call 124 # Test static call
89 self.assertEqual(self.run_test( 125 self.assertEqual(self.run_check_api_calls(
90 'public static void a(){}', 'void b(){Api.a();}'), 126 'public static void a(){}', 'void b(){Api.a();}'),
91 [False, ERROR_PREFIX + 'Impl/b -> Api/a:()V\n']) 127 [False, ERROR_PREFIX_CHECK_API_CALLS + 'Impl/b -> Api/a:()V\n'])
92 # Test virtual call 128 # Test virtual call
93 self.assertEqual(self.run_test( 129 self.assertEqual(self.run_check_api_calls(
94 'public void a(){}', 'void b(){new Api().a();}'), 130 'public void a(){}', 'void b(){new Api().a();}'),
95 [False, ERROR_PREFIX + 'Impl/b -> Api/a:()V\n']) 131 [False, ERROR_PREFIX_CHECK_API_CALLS + 'Impl/b -> Api/a:()V\n'])
132
133
134 def run_check_api_version(self, java):
135 OUT_FILENAME = 'out.txt'
136 return_code = os.system('./tools/update_api.py --api_jar %s > %s' %
137 (self.make_jar(java, 'Api'), OUT_FILENAME))
138 with open(API_FILENAME, 'r') as api_file:
139 api = api_file.read()
140 with open(API_VERSION_FILENAME, 'r') as api_version_file:
141 api_version = api_version_file.read()
142 with open(OUT_FILENAME, 'r') as out_file:
143 output = out_file.read()
144 return [return_code == 0, output, api, api_version]
145
146
147 def test_update_api_success(self):
148 # Test simple new API
149 self.assertEqual(self.run_check_api_version(
150 'public void a(){}'),
151 [True, '', CHECK_API_VERSION_PREFIX + """public class Api {
152 public Api();
153 public void a();
154 }
155 """, '1'])
156 # Test version number not increased when API not changed
157 self.assertEqual(self.run_check_api_version(
158 'public void a(){}'),
159 [True, '', CHECK_API_VERSION_PREFIX + """public class Api {
160 public Api();
161 public void a();
162 }
163 """, '1'])
164 # Test acceptable API method addition
165 self.assertEqual(self.run_check_api_version(
166 'public void a(){} public void b(){}'),
167 [True, '', CHECK_API_VERSION_PREFIX + """public class Api {
168 public Api();
169 public void a();
170 public void b();
171 }
172 """, '2'])
173 # Test version number not increased when API not changed
174 self.assertEqual(self.run_check_api_version(
175 'public void a(){} public void b(){}'),
176 [True, '', CHECK_API_VERSION_PREFIX + """public class Api {
177 public Api();
178 public void a();
179 public void b();
180 }
181 """, '2'])
182 # Test acceptable API class addition
183 self.assertEqual(self.run_check_api_version(
184 'public void a(){} public void b(){} public class C {}'),
185 [True, '', CHECK_API_VERSION_PREFIX + """public class Api$C {
186 public Api$C(Api);
187 }
188 public class Api {
189 public Api();
190 public void a();
191 public void b();
192 }
193 """, '3'])
194 # Test version number not increased when API not changed
195 self.assertEqual(self.run_check_api_version(
196 'public void a(){} public void b(){} public class C {}'),
197 [True, '', CHECK_API_VERSION_PREFIX + """public class Api$C {
198 public Api$C(Api);
199 }
200 public class Api {
201 public Api();
202 public void a();
203 public void b();
204 }
205 """, '3'])
206
207
208 def test_update_api_failure(self):
209 # Create a simple new API
210 self.assertEqual(self.run_check_api_version(
211 'public void a(){}'),
212 [True, '', CHECK_API_VERSION_PREFIX + """public class Api {
213 public Api();
214 public void a();
215 }
216 """, '1'])
217 # Test removing API method not allowed
218 self.assertEqual(self.run_check_api_version(''),
219 [False, ERROR_PREFIX_UPDATE_API + 'public void a();'
220 + ERROR_SUFFIX_UPDATE_API,
221 CHECK_API_VERSION_PREFIX + """public class Api {
222 public Api();
223 public void a();
224 }
225 """, '1'])
226 # Test modifying API method not allowed
227 self.assertEqual(self.run_check_api_version(
228 'public void a(int x){}'),
229 [False, ERROR_PREFIX_UPDATE_API + 'public void a();'
230 + ERROR_SUFFIX_UPDATE_API,
231 CHECK_API_VERSION_PREFIX + """public class Api {
232 public Api();
233 public void a();
234 }
235 """, '1'])
OLDNEW
« no previous file with comments | « components/cronet/tools/api_static_checks.py ('k') | components/cronet/tools/update_api.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698