| OLD | NEW |
| 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']) |
| OLD | NEW |