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

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

Powered by Google App Engine
This is Rietveld 408576698