1#!/usr/bin/env python3 2# Copyright 2012 The Chromium Authors 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6"""Tests for jni_generator.py. 7 8This test suite contains various tests for the JNI generator. 9It exercises the low-level parser all the way up to the 10code generator and ensures the output matches a golden 11file. 12""" 13 14import collections 15import copy 16import difflib 17import inspect 18import optparse 19import os 20import sys 21import tempfile 22import unittest 23import jni_generator 24import jni_registration_generator 25import zipfile 26from jni_generator import CalledByNative 27from jni_generator import NativeMethod 28from jni_generator import Param 29from jni_generator import ProxyHelpers 30 31_SCRIPT_NAME = 'base/android/jni_generator/jni_generator.py' 32_INCLUDES = ('base/android/jni_generator/jni_generator_helper.h') 33_JAVA_SRC_DIR = os.path.join('java', 'src', 'org', 'chromium', 'example', 34 'jni_generator') 35 36# Set this environment variable in order to regenerate the golden text 37# files. 38_REBASELINE_ENV = 'REBASELINE' 39 40 41def _RemoveHashedNames(natives): 42 ret = [] 43 for n in natives: 44 ret.append(jni_generator.NativeMethod(**n.__dict__)) 45 ret[-1].hashed_proxy_name = None 46 return ret 47 48 49class JniGeneratorOptions(object): 50 """The mock options object which is passed to the jni_generator.py script.""" 51 52 def __init__(self): 53 self.namespace = None 54 self.script_name = _SCRIPT_NAME 55 self.includes = _INCLUDES 56 self.ptr_type = 'long' 57 self.cpp = 'cpp' 58 self.javap = 'mock-javap' 59 self.enable_profiling = False 60 self.use_proxy_hash = False 61 self.enable_jni_multiplexing = False 62 self.always_mangle = False 63 self.unchecked_exceptions = False 64 self.split_name = None 65 self.include_test_only = True 66 self.package_prefix = None 67 68 69class JniRegistrationGeneratorOptions(object): 70 """The mock options object which is passed to the jni_generator.py script.""" 71 72 def __init__(self): 73 self.sources_exclusions = [] 74 self.namespace = None 75 self.enable_proxy_mocks = False 76 self.require_mocks = False 77 self.use_proxy_hash = False 78 self.enable_jni_multiplexing = False 79 self.manual_jni_registration = False 80 self.include_test_only = False 81 self.header_path = None 82 self.module_name = '' 83 self.package_prefix = None 84 85 86class BaseTest(unittest.TestCase): 87 88 @staticmethod 89 def _MergeRegistrationForTests(results, 90 header_guard='HEADER_GUARD', 91 namespace='test', 92 enable_jni_multiplexing=False): 93 94 results.sort(key=lambda d: d['FULL_CLASS_NAME']) 95 96 combined_dict = {} 97 for key in jni_registration_generator.MERGEABLE_KEYS: 98 combined_dict[key] = ''.join(d.get(key, '') for d in results) 99 100 combined_dict['HEADER_GUARD'] = header_guard 101 combined_dict['NAMESPACE'] = namespace 102 103 if enable_jni_multiplexing: 104 proxy_signatures_list = sorted( 105 set(combined_dict['PROXY_NATIVE_SIGNATURES'].split('\n'))) 106 combined_dict['PROXY_NATIVE_SIGNATURES'] = '\n'.join( 107 signature for signature in proxy_signatures_list) 108 109 proxy_native_array_list = sorted( 110 set(combined_dict['PROXY_NATIVE_METHOD_ARRAY'].split('},\n'))) 111 combined_dict['PROXY_NATIVE_METHOD_ARRAY'] = '},\n'.join( 112 p for p in proxy_native_array_list if p != '') + '}' 113 114 signature_to_cases = collections.defaultdict(list) 115 for d in results: 116 for signature, cases in d['SIGNATURE_TO_CASES'].items(): 117 signature_to_cases[signature].extend(cases) 118 combined_dict[ 119 'FORWARDING_CALLS'] = jni_registration_generator._AddForwardingCalls( 120 signature_to_cases, '', '') 121 122 return combined_dict 123 124 def _TestEndToEndRegistration(self, 125 input_java_src_files, 126 options, 127 name_to_goldens, 128 header_golden=None): 129 with tempfile.TemporaryDirectory() as tdir: 130 options.srcjar_path = os.path.join(tdir, 'srcjar.jar') 131 if header_golden: 132 options.header_path = os.path.join(tdir, 'header.h') 133 134 input_java_paths = [ 135 self._JoinScriptDir(os.path.join(_JAVA_SRC_DIR, f)) 136 for f in input_java_src_files 137 ] 138 139 jni_registration_generator._Generate(options, input_java_paths) 140 with zipfile.ZipFile(options.srcjar_path, 'r') as srcjar: 141 for name in srcjar.namelist(): 142 self.assertTrue( 143 name in name_to_goldens, 144 f'Found {name} output, but not present in name_to_goldens map.') 145 contents = srcjar.read(name).decode('utf-8') 146 self.AssertGoldenTextEquals(contents, 147 golden_file=name_to_goldens[name]) 148 if header_golden: 149 with open(options.header_path, 'r') as f: 150 # Temp directory will cause some diffs each time we run if we don't 151 # normalize. 152 contents = f.read().replace( 153 tdir.replace('/', '_').upper(), 'TEMP_DIR') 154 self.AssertGoldenTextEquals(contents, golden_file=header_golden) 155 156 def _JoinScriptDir(self, path): 157 script_dir = os.path.dirname(sys.argv[0]) 158 return os.path.join(script_dir, path) 159 160 def _JoinGoldenPath(self, golden_file_name): 161 return self._JoinScriptDir(os.path.join('golden', golden_file_name)) 162 163 def _ReadGoldenFile(self, golden_file_name): 164 golden_file_name = self._JoinGoldenPath(golden_file_name) 165 if not os.path.exists(golden_file_name): 166 return None 167 with open(golden_file_name, 'r') as f: 168 return f.read() 169 170 def _CreateJniHeaderFromFile(self, fname, qualified_clazz, options=None): 171 with open(self._JoinScriptDir(fname)) as f: 172 content = f.read() 173 opts = options 174 if opts is None: 175 opts = JniGeneratorOptions() 176 177 jni_from_java = jni_generator.JNIFromJavaSource(content, qualified_clazz, 178 opts) 179 return jni_from_java.GetContent() 180 181 def AssertObjEquals(self, first, second): 182 if isinstance(first, str): 183 return self.assertEqual(first, second) 184 dict_first = first.__dict__ 185 dict_second = second.__dict__ 186 self.assertEqual(dict_first.keys(), dict_second.keys()) 187 for key, value in dict_first.items(): 188 if (type(value) is list and len(value) 189 and isinstance(type(value[0]), object)): 190 self.AssertListEquals(value, second.__getattribute__(key)) 191 else: 192 actual = second.__getattribute__(key) 193 self.assertEqual(value, actual, 194 'Key ' + key + ': ' + str(value) + '!=' + str(actual)) 195 196 def AssertListEquals(self, first, second): 197 self.assertEqual(len(first), len(second)) 198 for i in range(len(first)): 199 if isinstance(first[i], object): 200 self.AssertObjEquals(first[i], second[i]) 201 else: 202 self.assertEqual(first[i], second[i]) 203 204 def AssertTextEquals(self, golden_text, generated_text): 205 if not self.CompareText(golden_text, generated_text): 206 self.fail('Golden text mismatch.') 207 208 def CompareText(self, golden_text, generated_text): 209 210 def FilterText(text): 211 return [ 212 l.strip() for l in text.split('\n') 213 if not l.startswith('// Copyright') 214 ] 215 216 stripped_golden = FilterText(golden_text) 217 stripped_generated = FilterText(generated_text) 218 if stripped_golden == stripped_generated: 219 return True 220 print(self.id()) 221 for line in difflib.context_diff(stripped_golden, stripped_generated): 222 print(line) 223 print('\n\nGenerated') 224 print('=' * 80) 225 print(generated_text) 226 print('=' * 80) 227 print('Run with:') 228 print('REBASELINE=1', sys.argv[0]) 229 print('to regenerate the data files.') 230 231 def AssertGoldenTextEquals(self, generated_text, suffix='', golden_file=None): 232 """Compares generated text with the corresponding golden_file 233 234 By default compares generated_text with the file at 235 script_dir/golden/{caller_name}[suffix].golden. If the parameter 236 golden_file is provided it will instead compare the generated text with 237 script_dir/golden/golden_file.""" 238 # This is the caller test method. 239 caller = inspect.stack()[1][3] 240 241 if golden_file is None: 242 self.assertTrue( 243 caller.startswith('test'), 244 'AssertGoldenTextEquals can only be called without at golden file ' 245 'from a test* method, not %s' % caller) 246 golden_file = '%s%s.golden' % (caller, suffix) 247 golden_text = self._ReadGoldenFile(golden_file) 248 if os.environ.get(_REBASELINE_ENV): 249 if golden_text != generated_text: 250 with open(self._JoinGoldenPath(golden_file), 'w') as f: 251 f.write(generated_text) 252 return 253 # golden_text is None if no file is found. Better to fail than in 254 # AssertTextEquals so we can give a clearer message. 255 if golden_text is None: 256 self.fail( 257 'Golden file %s does not exist.' % self._JoinGoldenPath(golden_file)) 258 self.AssertTextEquals(golden_text, generated_text) 259 260 261@unittest.skipIf(os.name == 'nt', 'Not intended to work on Windows') 262class TestGenerator(BaseTest): 263 264 def testInspectCaller(self): 265 266 def willRaise(): 267 # This function can only be called from a test* method. 268 self.AssertGoldenTextEquals('') 269 270 self.assertRaises(AssertionError, willRaise) 271 272 def testNatives(self): 273 test_data = """" 274 import android.graphics.Bitmap; 275 import android.view.View; 276 277 interface OnFrameAvailableListener {} 278 private native int nativeInit(); 279 private native void nativeDestroy(int nativeChromeBrowserProvider); 280 private native long nativeAddBookmark( 281 int nativeChromeBrowserProvider, 282 String url, String title, boolean isFolder, long parentId); 283 private static native String nativeGetDomainAndRegistry(String url); 284 private static native void nativeCreateHistoricalTabFromState( 285 byte[] state, int tab_index); 286 private native byte[] nativeGetStateAsByteArray(View view); 287 private static native String[] nativeGetAutofillProfileGUIDs(); 288 private native void nativeSetRecognitionResults( 289 int sessionId, String[] results); 290 private native long nativeAddBookmarkFromAPI( 291 int nativeChromeBrowserProvider, 292 String url, Long created, Boolean isBookmark, 293 Long date, byte[] favicon, String title, Integer visits); 294 native int nativeFindAll(String find); 295 private static native OnFrameAvailableListener nativeGetInnerClass(); 296 private native Bitmap nativeQueryBitmap( 297 int nativeChromeBrowserProvider, 298 String[] projection, String selection, 299 String[] selectionArgs, String sortOrder); 300 private native void nativeGotOrientation( 301 int nativeDataFetcherImplAndroid, 302 double alpha, double beta, double gamma); 303 private static native Throwable nativeMessWithJavaException(Throwable e); 304 """ 305 jni_params = jni_generator.JniParams( 306 'org/chromium/example/jni_generator/SampleForTests') 307 jni_params.ExtractImportsAndInnerClasses(test_data) 308 natives = jni_generator.ExtractNatives(test_data, 'int') 309 golden_natives = [ 310 NativeMethod( 311 return_type='int', 312 static=False, 313 name='Init', 314 params=[], 315 java_class_name=None), 316 NativeMethod( 317 return_type='void', 318 static=False, 319 name='Destroy', 320 params=[Param(datatype='int', name='nativeChromeBrowserProvider')], 321 java_class_name=None), 322 NativeMethod( 323 return_type='long', 324 static=False, 325 name='AddBookmark', 326 params=[ 327 Param(datatype='int', name='nativeChromeBrowserProvider'), 328 Param(datatype='String', name='url'), 329 Param(datatype='String', name='title'), 330 Param(datatype='boolean', name='isFolder'), 331 Param(datatype='long', name='parentId') 332 ], 333 java_class_name=None), 334 NativeMethod( 335 return_type='String', 336 static=True, 337 name='GetDomainAndRegistry', 338 params=[Param(datatype='String', name='url')], 339 java_class_name=None), 340 NativeMethod( 341 return_type='void', 342 static=True, 343 name='CreateHistoricalTabFromState', 344 params=[ 345 Param(datatype='byte[]', name='state'), 346 Param(datatype='int', name='tab_index') 347 ], 348 java_class_name=None), 349 NativeMethod( 350 return_type='byte[]', 351 static=False, 352 name='GetStateAsByteArray', 353 params=[Param(datatype='View', name='view')], 354 java_class_name=None), 355 NativeMethod( 356 return_type='String[]', 357 static=True, 358 name='GetAutofillProfileGUIDs', 359 params=[], 360 java_class_name=None), 361 NativeMethod( 362 return_type='void', 363 static=False, 364 name='SetRecognitionResults', 365 params=[ 366 Param(datatype='int', name='sessionId'), 367 Param(datatype='String[]', name='results') 368 ], 369 java_class_name=None), 370 NativeMethod( 371 return_type='long', 372 static=False, 373 name='AddBookmarkFromAPI', 374 params=[ 375 Param(datatype='int', name='nativeChromeBrowserProvider'), 376 Param(datatype='String', name='url'), 377 Param(datatype='Long', name='created'), 378 Param(datatype='Boolean', name='isBookmark'), 379 Param(datatype='Long', name='date'), 380 Param(datatype='byte[]', name='favicon'), 381 Param(datatype='String', name='title'), 382 Param(datatype='Integer', name='visits') 383 ], 384 java_class_name=None), 385 NativeMethod( 386 return_type='int', 387 static=False, 388 name='FindAll', 389 params=[Param(datatype='String', name='find')], 390 java_class_name=None), 391 NativeMethod( 392 return_type='OnFrameAvailableListener', 393 static=True, 394 name='GetInnerClass', 395 params=[], 396 java_class_name=None), 397 NativeMethod( 398 return_type='Bitmap', 399 static=False, 400 name='QueryBitmap', 401 params=[ 402 Param(datatype='int', name='nativeChromeBrowserProvider'), 403 Param(datatype='String[]', name='projection'), 404 Param(datatype='String', name='selection'), 405 Param(datatype='String[]', name='selectionArgs'), 406 Param(datatype='String', name='sortOrder'), 407 ], 408 java_class_name=None), 409 NativeMethod( 410 return_type='void', 411 static=False, 412 name='GotOrientation', 413 params=[ 414 Param(datatype='int', name='nativeDataFetcherImplAndroid'), 415 Param(datatype='double', name='alpha'), 416 Param(datatype='double', name='beta'), 417 Param(datatype='double', name='gamma'), 418 ], 419 java_class_name=None), 420 NativeMethod( 421 return_type='Throwable', 422 static=True, 423 name='MessWithJavaException', 424 params=[Param(datatype='Throwable', name='e')], 425 java_class_name=None) 426 ] 427 self.AssertListEquals(golden_natives, natives) 428 h1 = jni_generator.InlHeaderFileGenerator('', '', 'org/chromium/TestJni', 429 natives, [], [], jni_params, 430 JniGeneratorOptions()) 431 self.AssertGoldenTextEquals(h1.GetContent()) 432 h2 = jni_registration_generator.DictionaryGenerator(JniGeneratorOptions(), 433 '', '', 434 'org/chromium/TestJni', 435 natives, jni_params) 436 content = TestGenerator._MergeRegistrationForTests([h2.Generate()]) 437 438 reg_options = JniRegistrationGeneratorOptions() 439 reg_options.manual_jni_registration = True 440 self.AssertGoldenTextEquals(jni_registration_generator.CreateFromDict( 441 reg_options, '', content), 442 suffix='Registrations') 443 444 def testInnerClassNatives(self): 445 test_data = """ 446 class MyInnerClass { 447 @NativeCall("MyInnerClass") 448 private native int nativeInit(); 449 } 450 """ 451 natives = jni_generator.ExtractNatives(test_data, 'int') 452 golden_natives = [ 453 NativeMethod( 454 return_type='int', 455 static=False, 456 name='Init', 457 params=[], 458 java_class_name='MyInnerClass') 459 ] 460 self.AssertListEquals(golden_natives, natives) 461 jni_params = jni_generator.JniParams('') 462 h = jni_generator.InlHeaderFileGenerator('', '', 'org/chromium/TestJni', 463 natives, [], [], jni_params, 464 JniGeneratorOptions()) 465 self.AssertGoldenTextEquals(h.GetContent()) 466 467 def testInnerClassNativesMultiple(self): 468 test_data = """ 469 class MyInnerClass { 470 @NativeCall("MyInnerClass") 471 private native int nativeInit(); 472 } 473 class MyOtherInnerClass { 474 @NativeCall("MyOtherInnerClass") 475 private native int nativeInit(); 476 } 477 """ 478 natives = jni_generator.ExtractNatives(test_data, 'int') 479 golden_natives = [ 480 NativeMethod( 481 return_type='int', 482 static=False, 483 name='Init', 484 params=[], 485 java_class_name='MyInnerClass'), 486 NativeMethod( 487 return_type='int', 488 static=False, 489 name='Init', 490 params=[], 491 java_class_name='MyOtherInnerClass') 492 ] 493 self.AssertListEquals(golden_natives, natives) 494 jni_params = jni_generator.JniParams('') 495 h = jni_generator.InlHeaderFileGenerator('', '', 'org/chromium/TestJni', 496 natives, [], [], jni_params, 497 JniGeneratorOptions()) 498 self.AssertGoldenTextEquals(h.GetContent()) 499 500 def testInnerClassNativesBothInnerAndOuter(self): 501 test_data = """ 502 class MyOuterClass { 503 private native int nativeInit(); 504 class MyOtherInnerClass { 505 @NativeCall("MyOtherInnerClass") 506 private native int nativeInit(); 507 } 508 } 509 """ 510 natives = jni_generator.ExtractNatives(test_data, 'int') 511 golden_natives = [ 512 NativeMethod( 513 return_type='int', 514 static=False, 515 name='Init', 516 params=[], 517 java_class_name=None), 518 NativeMethod( 519 return_type='int', 520 static=False, 521 name='Init', 522 params=[], 523 java_class_name='MyOtherInnerClass') 524 ] 525 self.AssertListEquals(golden_natives, natives) 526 jni_params = jni_generator.JniParams('') 527 h = jni_generator.InlHeaderFileGenerator('', '', 'org/chromium/TestJni', 528 natives, [], [], jni_params, 529 JniGeneratorOptions()) 530 self.AssertGoldenTextEquals(h.GetContent()) 531 532 h2 = jni_registration_generator.DictionaryGenerator(JniGeneratorOptions(), 533 '', '', 534 'org/chromium/TestJni', 535 natives, jni_params) 536 content = TestGenerator._MergeRegistrationForTests([h2.Generate()]) 537 538 reg_options = JniRegistrationGeneratorOptions() 539 reg_options.manual_jni_registration = True 540 self.AssertGoldenTextEquals(jni_registration_generator.CreateFromDict( 541 reg_options, '', content), 542 suffix='Registrations') 543 544 def testCalledByNatives(self): 545 test_data = """" 546 import android.graphics.Bitmap; 547 import android.view.View; 548 import java.io.InputStream; 549 import java.util.List; 550 551 class InnerClass {} 552 553 @CalledByNative 554 @SomeOtherA 555 @SomeOtherB 556 public InnerClass showConfirmInfoBar(int nativeInfoBar, 557 String buttonOk, String buttonCancel, String title, Bitmap icon) { 558 InfoBar infobar = new ConfirmInfoBar(nativeInfoBar, mContext, 559 buttonOk, buttonCancel, 560 title, icon); 561 return infobar; 562 } 563 @CalledByNative 564 InnerClass showAutoLoginInfoBar(int nativeInfoBar, 565 String realm, String account, String args) { 566 AutoLoginInfoBar infobar = new AutoLoginInfoBar(nativeInfoBar, mContext, 567 realm, account, args); 568 if (infobar.displayedAccountCount() == 0) 569 infobar = null; 570 return infobar; 571 } 572 @CalledByNative("InfoBar") 573 void dismiss(); 574 @SuppressWarnings("unused") 575 @CalledByNative 576 private static boolean shouldShowAutoLogin(View view, 577 String realm, String account, String args) { 578 AccountManagerContainer accountManagerContainer = 579 new AccountManagerContainer((Activity)contentView.getContext(), 580 realm, account, args); 581 String[] logins = accountManagerContainer.getAccountLogins(null); 582 return logins.length != 0; 583 } 584 @CalledByNative 585 static InputStream openUrl(String url) { 586 return null; 587 } 588 @CalledByNative 589 private void activateHardwareAcceleration(final boolean activated, 590 final int iPid, final int iType, 591 final int iPrimaryID, final int iSecondaryID) { 592 if (!activated) { 593 return 594 } 595 } 596 @CalledByNative 597 public static @Status int updateStatus(@Status int status) { 598 return getAndUpdateStatus(status); 599 } 600 @CalledByNativeUnchecked 601 private void uncheckedCall(int iParam); 602 603 @CalledByNative 604 public byte[] returnByteArray(); 605 606 @CalledByNative 607 public boolean[] returnBooleanArray(); 608 609 @CalledByNative 610 public char[] returnCharArray(); 611 612 @CalledByNative 613 public short[] returnShortArray(); 614 615 @CalledByNative 616 public int[] returnIntArray(); 617 618 @CalledByNative 619 public long[] returnLongArray(); 620 621 @CalledByNative 622 public double[] returnDoubleArray(); 623 624 @CalledByNative 625 public Object[] returnObjectArray(); 626 627 @CalledByNative 628 public byte[][] returnArrayOfByteArray(); 629 630 @CalledByNative 631 public Bitmap.CompressFormat getCompressFormat(); 632 633 @CalledByNative 634 public List<Bitmap.CompressFormat> getCompressFormatList(); 635 636 @CalledByNativeForTesting 637 public int[] returnIntArrayForTesting(); 638 """ 639 jni_params = jni_generator.JniParams('org/chromium/Foo') 640 jni_params.ExtractImportsAndInnerClasses(test_data) 641 called_by_natives = jni_generator.ExtractCalledByNatives( 642 jni_params, test_data, always_mangle=False) 643 golden_called_by_natives = [ 644 CalledByNative( 645 return_type='InnerClass', 646 system_class=False, 647 static=False, 648 name='showConfirmInfoBar', 649 method_id_var_name='showConfirmInfoBar', 650 java_class_name='', 651 params=[ 652 Param(datatype='int', name='nativeInfoBar'), 653 Param(datatype='String', name='buttonOk'), 654 Param(datatype='String', name='buttonCancel'), 655 Param(datatype='String', name='title'), 656 Param(datatype='Bitmap', name='icon') 657 ], 658 env_call=('Object', ''), 659 unchecked=False, 660 ), 661 CalledByNative( 662 return_type='InnerClass', 663 system_class=False, 664 static=False, 665 name='showAutoLoginInfoBar', 666 method_id_var_name='showAutoLoginInfoBar', 667 java_class_name='', 668 params=[ 669 Param(datatype='int', name='nativeInfoBar'), 670 Param(datatype='String', name='realm'), 671 Param(datatype='String', name='account'), 672 Param(datatype='String', name='args') 673 ], 674 env_call=('Object', ''), 675 unchecked=False, 676 ), 677 CalledByNative( 678 return_type='void', 679 system_class=False, 680 static=False, 681 name='dismiss', 682 method_id_var_name='dismiss', 683 java_class_name='InfoBar', 684 params=[], 685 env_call=('Void', ''), 686 unchecked=False, 687 ), 688 CalledByNative( 689 return_type='boolean', 690 system_class=False, 691 static=True, 692 name='shouldShowAutoLogin', 693 method_id_var_name='shouldShowAutoLogin', 694 java_class_name='', 695 params=[ 696 Param(datatype='View', name='view'), 697 Param(datatype='String', name='realm'), 698 Param(datatype='String', name='account'), 699 Param(datatype='String', name='args') 700 ], 701 env_call=('Boolean', ''), 702 unchecked=False, 703 ), 704 CalledByNative( 705 return_type='InputStream', 706 system_class=False, 707 static=True, 708 name='openUrl', 709 method_id_var_name='openUrl', 710 java_class_name='', 711 params=[Param(datatype='String', name='url')], 712 env_call=('Object', ''), 713 unchecked=False, 714 ), 715 CalledByNative( 716 return_type='void', 717 system_class=False, 718 static=False, 719 name='activateHardwareAcceleration', 720 method_id_var_name='activateHardwareAcceleration', 721 java_class_name='', 722 params=[ 723 Param(datatype='boolean', name='activated'), 724 Param(datatype='int', name='iPid'), 725 Param(datatype='int', name='iType'), 726 Param(datatype='int', name='iPrimaryID'), 727 Param(datatype='int', name='iSecondaryID'), 728 ], 729 env_call=('Void', ''), 730 unchecked=False, 731 ), 732 CalledByNative( 733 return_type='int', 734 system_class=False, 735 static=True, 736 name='updateStatus', 737 method_id_var_name='updateStatus', 738 java_class_name='', 739 params=[ 740 Param(annotations=['@Status'], datatype='int', name='status') 741 ], 742 env_call=('Integer', ''), 743 unchecked=False, 744 ), 745 CalledByNative( 746 return_type='void', 747 system_class=False, 748 static=False, 749 name='uncheckedCall', 750 method_id_var_name='uncheckedCall', 751 java_class_name='', 752 params=[Param(datatype='int', name='iParam')], 753 env_call=('Void', ''), 754 unchecked=True, 755 ), 756 CalledByNative( 757 return_type='byte[]', 758 system_class=False, 759 static=False, 760 name='returnByteArray', 761 method_id_var_name='returnByteArray', 762 java_class_name='', 763 params=[], 764 env_call=('Void', ''), 765 unchecked=False, 766 ), 767 CalledByNative( 768 return_type='boolean[]', 769 system_class=False, 770 static=False, 771 name='returnBooleanArray', 772 method_id_var_name='returnBooleanArray', 773 java_class_name='', 774 params=[], 775 env_call=('Void', ''), 776 unchecked=False, 777 ), 778 CalledByNative( 779 return_type='char[]', 780 system_class=False, 781 static=False, 782 name='returnCharArray', 783 method_id_var_name='returnCharArray', 784 java_class_name='', 785 params=[], 786 env_call=('Void', ''), 787 unchecked=False, 788 ), 789 CalledByNative( 790 return_type='short[]', 791 system_class=False, 792 static=False, 793 name='returnShortArray', 794 method_id_var_name='returnShortArray', 795 java_class_name='', 796 params=[], 797 env_call=('Void', ''), 798 unchecked=False, 799 ), 800 CalledByNative( 801 return_type='int[]', 802 system_class=False, 803 static=False, 804 name='returnIntArray', 805 method_id_var_name='returnIntArray', 806 java_class_name='', 807 params=[], 808 env_call=('Void', ''), 809 unchecked=False, 810 ), 811 CalledByNative( 812 return_type='long[]', 813 system_class=False, 814 static=False, 815 name='returnLongArray', 816 method_id_var_name='returnLongArray', 817 java_class_name='', 818 params=[], 819 env_call=('Void', ''), 820 unchecked=False, 821 ), 822 CalledByNative( 823 return_type='double[]', 824 system_class=False, 825 static=False, 826 name='returnDoubleArray', 827 method_id_var_name='returnDoubleArray', 828 java_class_name='', 829 params=[], 830 env_call=('Void', ''), 831 unchecked=False, 832 ), 833 CalledByNative( 834 return_type='Object[]', 835 system_class=False, 836 static=False, 837 name='returnObjectArray', 838 method_id_var_name='returnObjectArray', 839 java_class_name='', 840 params=[], 841 env_call=('Void', ''), 842 unchecked=False, 843 ), 844 CalledByNative( 845 return_type='byte[][]', 846 system_class=False, 847 static=False, 848 name='returnArrayOfByteArray', 849 method_id_var_name='returnArrayOfByteArray', 850 java_class_name='', 851 params=[], 852 env_call=('Void', ''), 853 unchecked=False, 854 ), 855 CalledByNative( 856 return_type='Bitmap.CompressFormat', 857 system_class=False, 858 static=False, 859 name='getCompressFormat', 860 method_id_var_name='getCompressFormat', 861 java_class_name='', 862 params=[], 863 env_call=('Void', ''), 864 unchecked=False, 865 ), 866 CalledByNative( 867 return_type='List<Bitmap.CompressFormat>', 868 system_class=False, 869 static=False, 870 name='getCompressFormatList', 871 method_id_var_name='getCompressFormatList', 872 java_class_name='', 873 params=[], 874 env_call=('Void', ''), 875 unchecked=False, 876 ), 877 CalledByNative( 878 return_type='int[]', 879 system_class=False, 880 static=False, 881 name='returnIntArrayForTesting', 882 method_id_var_name='returnIntArrayForTesting', 883 java_class_name='', 884 params=[], 885 env_call=('Void', ''), 886 unchecked=False, 887 ), 888 ] 889 self.AssertListEquals(golden_called_by_natives, called_by_natives) 890 h = jni_generator.InlHeaderFileGenerator('', '', 'org/chromium/TestJni', [], 891 called_by_natives, [], jni_params, 892 JniGeneratorOptions()) 893 self.AssertGoldenTextEquals(h.GetContent()) 894 895 def testCalledByNativeParseError(self): 896 try: 897 jni_params = jni_generator.JniParams('') 898 jni_generator.ExtractCalledByNatives( 899 jni_params, 900 """ 901@CalledByNative 902public static int foo(); // This one is fine 903 904@CalledByNative 905scooby doo 906""", 907 always_mangle=False) 908 self.fail('Expected a ParseError') 909 except jni_generator.ParseError as e: 910 self.assertEqual(('@CalledByNative', 'scooby doo'), e.context_lines) 911 912 def testFullyQualifiedClassName(self): 913 contents = """ 914// Copyright 2010 The Chromium Authors 915// Use of this source code is governed by a BSD-style license that can be 916// found in the LICENSE file. 917 918package org.chromium.content.browser; 919 920import org.chromium.base.BuildInfo; 921""" 922 self.assertEqual( 923 'org/chromium/content/browser/Foo', 924 jni_generator.ExtractFullyQualifiedJavaClassName( 925 'org/chromium/content/browser/Foo.java', contents)) 926 self.assertEqual( 927 'org/chromium/content/browser/Foo', 928 jni_generator.ExtractFullyQualifiedJavaClassName( 929 'frameworks/Foo.java', contents)) 930 self.assertRaises(SyntaxError, 931 jni_generator.ExtractFullyQualifiedJavaClassName, 932 'com/foo/Bar', 'no PACKAGE line') 933 self.assertRaises(AssertionError, 934 jni_generator.ExtractFullyQualifiedJavaClassName, 935 'com/foo/Bar.kt', 'Kotlin not supported') 936 937 def testMethodNameMangling(self): 938 jni_params = jni_generator.JniParams('') 939 self.assertEqual( 940 'closeV', 941 jni_generator.GetMangledMethodName(jni_params, 'close', [], 'void')) 942 self.assertEqual( 943 'readI_AB_I_I', 944 jni_generator.GetMangledMethodName(jni_params, 'read', [ 945 Param(name='p1', datatype='byte[]'), 946 Param(name='p2', datatype='int'), 947 Param(name='p3', datatype='int'), 948 ], 'int')) 949 self.assertEqual( 950 'openJIIS_JLS', 951 jni_generator.GetMangledMethodName(jni_params, 'open', [ 952 Param(name='p1', datatype='java/lang/String'), 953 ], 'java/io/InputStream')) 954 955 def testMethodNameAlwaysMangle(self): 956 test_data = """ 957 import f.o.o.Bar; 958 import f.o.o.Baz; 959 960 class Clazz { 961 @CalledByNative 962 public Baz methodz(Bar bar) { 963 return null; 964 } 965 } 966 """ 967 jni_params = jni_generator.JniParams('org/chromium/Foo') 968 jni_params.ExtractImportsAndInnerClasses(test_data) 969 called_by_natives = jni_generator.ExtractCalledByNatives( 970 jni_params, test_data, always_mangle=True) 971 self.assertEqual(1, len(called_by_natives)) 972 method = called_by_natives[0] 973 self.assertEqual('methodzFOOB_FOOB', method.method_id_var_name) 974 975 def testFromJavaPGenerics(self): 976 contents = """ 977public abstract class java.util.HashSet<T> extends java.util.AbstractSet<E> 978 implements java.util.Set<E>, java.lang.Cloneable, java.io.Serializable { 979 public void dummy(); 980 Signature: ()V 981 public java.lang.Class<?> getClass(); 982 Signature: ()Ljava/lang/Class<*>; 983 public static void overloadWithVarargs(java.lang.String...); 984 Signature: ([Ljava/lang/String;)V 985 public static void overloadWithVarargs(android.icu.text.DisplayContext...); 986 Signature: ([Landroid/icu/text/DisplayContext;)V 987} 988""" 989 jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'), 990 JniGeneratorOptions()) 991 self.AssertGoldenTextEquals(jni_from_javap.GetContent()) 992 993 def testSnippnetJavap6_7_8(self): 994 content_javap6 = """ 995public class java.util.HashSet { 996public boolean add(java.lang.Object); 997 Signature: (Ljava/lang/Object;)Z 998} 999""" 1000 1001 content_javap7 = """ 1002public class java.util.HashSet { 1003public boolean add(E); 1004 Signature: (Ljava/lang/Object;)Z 1005} 1006""" 1007 1008 content_javap8 = """ 1009public class java.util.HashSet { 1010 public boolean add(E); 1011 descriptor: (Ljava/lang/Object;)Z 1012} 1013""" 1014 1015 jni_from_javap6 = jni_generator.JNIFromJavaP(content_javap6.split('\n'), 1016 JniGeneratorOptions()) 1017 jni_from_javap7 = jni_generator.JNIFromJavaP(content_javap7.split('\n'), 1018 JniGeneratorOptions()) 1019 jni_from_javap8 = jni_generator.JNIFromJavaP(content_javap8.split('\n'), 1020 JniGeneratorOptions()) 1021 self.assertTrue(jni_from_javap6.GetContent()) 1022 self.assertTrue(jni_from_javap7.GetContent()) 1023 self.assertTrue(jni_from_javap8.GetContent()) 1024 # Ensure the javap7 is correctly parsed and uses the Signature field rather 1025 # than the "E" parameter. 1026 self.AssertTextEquals(jni_from_javap6.GetContent(), 1027 jni_from_javap7.GetContent()) 1028 # Ensure the javap8 is correctly parsed and uses the descriptor field. 1029 self.AssertTextEquals(jni_from_javap7.GetContent(), 1030 jni_from_javap8.GetContent()) 1031 1032 def testFromJavaP(self): 1033 contents = self._ReadGoldenFile('testInputStream.javap') 1034 jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'), 1035 JniGeneratorOptions()) 1036 self.assertEqual(10, len(jni_from_javap.called_by_natives)) 1037 self.AssertGoldenTextEquals(jni_from_javap.GetContent()) 1038 1039 def testConstantsFromJavaP(self): 1040 for f in ['testMotionEvent.javap', 'testMotionEvent.javap7']: 1041 contents = self._ReadGoldenFile(f) 1042 jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'), 1043 JniGeneratorOptions()) 1044 self.assertEqual(86, len(jni_from_javap.called_by_natives)) 1045 self.AssertGoldenTextEquals(jni_from_javap.GetContent()) 1046 1047 def testREForNatives(self): 1048 # We should not match "native SyncSetupFlow" inside the comment. 1049 test_data = """ 1050 /** 1051 * Invoked when the setup process is complete so we can disconnect from the 1052 * private native void nativeSyncSetupFlowHandler();. 1053 */ 1054 public void destroy() { 1055 Log.v(TAG, "Destroying native SyncSetupFlow"); 1056 if (mNativeSyncSetupFlow != 0) { 1057 nativeSyncSetupEnded(mNativeSyncSetupFlow); 1058 mNativeSyncSetupFlow = 0; 1059 } 1060 } 1061 private native void nativeSyncSetupEnded( 1062 int nativeAndroidSyncSetupFlowHandler); 1063 """ 1064 jni_from_java = jni_generator.JNIFromJavaSource(test_data, 'foo/bar', 1065 JniGeneratorOptions()) 1066 self.AssertGoldenTextEquals(jni_from_java.GetContent()) 1067 1068 def testRaisesOnNonJNIMethod(self): 1069 test_data = """ 1070 class MyInnerClass { 1071 private int Foo(int p0) { 1072 } 1073 } 1074 """ 1075 self.assertRaises(SyntaxError, jni_generator.JNIFromJavaSource, test_data, 1076 'foo/bar', JniGeneratorOptions()) 1077 1078 def testJniSelfDocumentingExample(self): 1079 generated_text = self._CreateJniHeaderFromFile( 1080 os.path.join(_JAVA_SRC_DIR, 'SampleForTests.java'), 1081 'org/chromium/example/jni_generator/SampleForTests') 1082 self.AssertGoldenTextEquals( 1083 generated_text, golden_file='SampleForTests_jni.golden') 1084 1085 def testNoWrappingPreprocessorLines(self): 1086 test_data = """ 1087 package com.google.lookhowextremelylongiam.snarf.icankeepthisupallday; 1088 1089 class ReallyLongClassNamesAreAllTheRage { 1090 private static native int nativeTest(); 1091 } 1092 """ 1093 jni_from_java = jni_generator.JNIFromJavaSource( 1094 test_data, ('com/google/lookhowextremelylongiam/snarf/' 1095 'icankeepthisupallday/ReallyLongClassNamesAreAllTheRage'), 1096 JniGeneratorOptions()) 1097 jni_lines = jni_from_java.GetContent().split('\n') 1098 line = next( 1099 line for line in jni_lines if line.lstrip().startswith('#ifndef')) 1100 self.assertTrue( 1101 len(line) > 80, ('Expected #ifndef line to be > 80 chars: ', line)) 1102 1103 def testImports(self): 1104 import_header = """ 1105// Copyright 2012 The Chromium Authors 1106// Use of this source code is governed by a BSD-style license that can be 1107// found in the LICENSE file. 1108 1109package org.chromium.content.app; 1110 1111import android.app.Service; 1112import android.content.Context; 1113import android.content.Intent; 1114import android.graphics.SurfaceTexture; 1115import android.os.Bundle; 1116import android.os.IBinder; 1117import android.os.ParcelFileDescriptor; 1118import android.os.Process; 1119import android.os.RemoteException; 1120import android.util.Log; 1121import android.view.Surface; 1122 1123import java.util.ArrayList; 1124 1125import org.chromium.base.annotations.CalledByNative; 1126import org.chromium.base.annotations.JNINamespace; 1127import org.chromium.content.app.ContentMain; 1128import org.chromium.content.browser.SandboxedProcessConnection; 1129import org.chromium.content.common.ISandboxedProcessCallback; 1130import org.chromium.content.common.ISandboxedProcessService; 1131import org.chromium.content.common.WillNotRaise.AnException; 1132import org.chromium.content.common.WillRaise.AnException; 1133 1134import static org.chromium.Bar.Zoo; 1135 1136class Foo { 1137 public static class BookmarkNode implements Parcelable { 1138 } 1139 public interface PasswordListObserver { 1140 } 1141} 1142 """ 1143 jni_params = jni_generator.JniParams('org/chromium/content/app/Foo') 1144 jni_params.ExtractImportsAndInnerClasses(import_header) 1145 self.assertTrue('Lorg/chromium/content/common/ISandboxedProcessService' in 1146 jni_params._imports) 1147 self.assertTrue('Lorg/chromium/Bar/Zoo' in jni_params._imports) 1148 self.assertTrue('Lorg/chromium/content/app/Foo$BookmarkNode' in jni_params. 1149 _inner_classes) 1150 self.assertTrue('Lorg/chromium/content/app/Foo$PasswordListObserver' in 1151 jni_params._inner_classes) 1152 self.assertEqual('Lorg/chromium/content/app/ContentMain$Inner;', 1153 jni_params.JavaToJni('ContentMain.Inner')) 1154 self.assertRaises(SyntaxError, jni_params.JavaToJni, 'AnException') 1155 1156 def testJniParamsJavaToJni(self): 1157 jni_params = jni_generator.JniParams('') 1158 self.AssertTextEquals('I', jni_params.JavaToJni('int')) 1159 self.AssertTextEquals('[B', jni_params.JavaToJni('byte[]')) 1160 self.AssertTextEquals('[Ljava/nio/ByteBuffer;', 1161 jni_params.JavaToJni('java/nio/ByteBuffer[]')) 1162 1163 def testNativesLong(self): 1164 test_options = JniGeneratorOptions() 1165 test_options.ptr_type = 'long' 1166 test_data = """" 1167 private native void nativeDestroy(long nativeChromeBrowserProvider); 1168 """ 1169 jni_params = jni_generator.JniParams('') 1170 jni_params.ExtractImportsAndInnerClasses(test_data) 1171 natives = jni_generator.ExtractNatives(test_data, test_options.ptr_type) 1172 golden_natives = [ 1173 NativeMethod( 1174 return_type='void', 1175 static=False, 1176 name='Destroy', 1177 params=[Param(datatype='long', name='nativeChromeBrowserProvider')], 1178 java_class_name=None, 1179 ptr_type=test_options.ptr_type), 1180 ] 1181 self.AssertListEquals(golden_natives, natives) 1182 h = jni_generator.InlHeaderFileGenerator('', '', 'org/chromium/TestJni', 1183 natives, [], [], jni_params, 1184 test_options) 1185 self.AssertGoldenTextEquals(h.GetContent()) 1186 1187 def testNativeExportsOnlyOption(self): 1188 test_data = """ 1189 package org.chromium.example.jni_generator; 1190 1191 /** The pointer to the native Test. */ 1192 long nativeTest; 1193 1194 class Test { 1195 private static native int nativeStaticMethod(long nativeTest, int arg1); 1196 private native int nativeMethod(long nativeTest, int arg1); 1197 @CalledByNative 1198 private void testMethodWithParam(int iParam); 1199 @CalledByNative 1200 private String testMethodWithParamAndReturn(int iParam); 1201 @CalledByNative 1202 private static int testStaticMethodWithParam(int iParam); 1203 @CalledByNative 1204 private static double testMethodWithNoParam(); 1205 @CalledByNative 1206 private static String testStaticMethodWithNoParam(); 1207 1208 class MyInnerClass { 1209 @NativeCall("MyInnerClass") 1210 private native int nativeInit(); 1211 } 1212 class MyOtherInnerClass { 1213 @NativeCall("MyOtherInnerClass") 1214 private native int nativeInit(); 1215 } 1216 } 1217 """ 1218 options = JniGeneratorOptions() 1219 jni_from_java = jni_generator.JNIFromJavaSource( 1220 test_data, 'org/chromium/example/jni_generator/SampleForTests', options) 1221 self.AssertGoldenTextEquals(jni_from_java.GetContent()) 1222 1223 def testOuterInnerRaises(self): 1224 test_data = """ 1225 package org.chromium.media; 1226 1227 @CalledByNative 1228 static int getCaptureFormatWidth(VideoCapture.CaptureFormat format) { 1229 return format.getWidth(); 1230 } 1231 """ 1232 1233 def willRaise(): 1234 jni_generator.JNIFromJavaSource(test_data, 1235 'org/chromium/media/VideoCaptureFactory', 1236 JniGeneratorOptions()) 1237 1238 self.assertRaises(SyntaxError, willRaise) 1239 1240 def testSingleJNIAdditionalImport(self): 1241 test_data = """ 1242 package org.chromium.foo; 1243 1244 @JNIAdditionalImport(Bar.class) 1245 class Foo { 1246 1247 @CalledByNative 1248 private static void calledByNative(Bar.Callback callback) { 1249 } 1250 1251 private static native void nativeDoSomething(Bar.Callback callback); 1252 } 1253 """ 1254 jni_from_java = jni_generator.JNIFromJavaSource(test_data, 1255 'org/chromium/foo/Foo', 1256 JniGeneratorOptions()) 1257 self.AssertGoldenTextEquals(jni_from_java.GetContent()) 1258 1259 def testMultipleJNIAdditionalImport(self): 1260 test_data = """ 1261 package org.chromium.foo; 1262 1263 @JNIAdditionalImport({Bar1.class, Bar2.class}) 1264 class Foo { 1265 1266 @CalledByNative 1267 private static void calledByNative(Bar1.Callback callback1, 1268 Bar2.Callback callback2) { 1269 } 1270 1271 private static native void nativeDoSomething(Bar1.Callback callback1, 1272 Bar2.Callback callback2); 1273 } 1274 """ 1275 jni_from_java = jni_generator.JNIFromJavaSource(test_data, 1276 'org/chromium/foo/Foo', 1277 JniGeneratorOptions()) 1278 self.AssertGoldenTextEquals(jni_from_java.GetContent()) 1279 1280 def testStaticBindingCaller(self): 1281 test_data = """ 1282 package org.chromium.foo; 1283 1284 class Bar { 1285 static native void nativeShouldBindCaller(Object caller); 1286 static native void nativeShouldBindCaller(Object caller, int a); 1287 static native void nativeFoo(long nativeNativeObject, Bar caller); 1288 static native void nativeFoo(long nativeNativeObject, Bar caller, int a); 1289 native void nativeCallNativeMethod(long nativePtr); 1290 @NativeClassQualifiedName("Foo::Bar") 1291 native void nativeCallWithQualifiedObject(long nativePtr); 1292 } 1293 """ 1294 1295 jni_from_java = jni_generator.JNIFromJavaSource(test_data, 1296 'org/chromium/foo/Foo', 1297 JniGeneratorOptions()) 1298 self.AssertGoldenTextEquals(jni_from_java.GetContent()) 1299 1300 def testSplitNameExample(self): 1301 opts = JniGeneratorOptions() 1302 opts.split_name = "sample" 1303 generated_text = self._CreateJniHeaderFromFile( 1304 os.path.join(_JAVA_SRC_DIR, 'SampleForTests.java'), 1305 'org/chromium/example/jni_generator/SampleForTests', opts) 1306 self.AssertGoldenTextEquals( 1307 generated_text, golden_file='SampleForTestsWithSplit_jni.golden') 1308 1309 1310@unittest.skipIf(os.name == 'nt', 'Not intended to work on Windows') 1311class ProxyTestGenerator(BaseTest): 1312 1313 def _BuildRegDictFromSample(self): 1314 path = self._JoinScriptDir( 1315 os.path.join(_JAVA_SRC_DIR, 'SampleForAnnotationProcessor.java')) 1316 reg_dict = jni_registration_generator._DictForPath( 1317 JniRegistrationGeneratorOptions(), path) 1318 reg_dict = self._MergeRegistrationForTests([reg_dict]) 1319 1320 return reg_dict 1321 1322 def testEndToEndProxyHashed(self): 1323 input_java_files = ['SampleForAnnotationProcessor.java'] 1324 options = JniRegistrationGeneratorOptions() 1325 options.use_proxy_hash = True 1326 name_to_goldens = { 1327 'org/chromium/base/natives/GEN_JNI.java': 1328 'HashedSampleForAnnotationProcessorGenJni.2.golden', 1329 'J/N.java': 'HashedSampleForAnnotationProcessorGenJni.golden' 1330 } 1331 self._TestEndToEndRegistration(input_java_files, options, name_to_goldens) 1332 1333 def testEndToEndManualRegistration(self): 1334 input_java_files = ['SampleForAnnotationProcessor.java'] 1335 options = JniRegistrationGeneratorOptions() 1336 options.manual_jni_registration = True 1337 name_to_goldens = { 1338 'org/chromium/base/natives/GEN_JNI.java': 1339 'SampleForAnnotationProcessorGenJni.golden' 1340 } 1341 self._TestEndToEndRegistration( 1342 input_java_files, 1343 options, 1344 name_to_goldens, 1345 header_golden='SampleForAnnotationProcessorManualJni.golden') 1346 1347 def testEndToEndProxyJniWithModules(self): 1348 input_java_files = [ 1349 'SampleForAnnotationProcessor.java', 'SampleModule.java' 1350 ] 1351 options = JniRegistrationGeneratorOptions() 1352 options.use_proxy_hash = True 1353 options.module_name = 'module' 1354 name_to_goldens = { 1355 'org/chromium/base/natives/GEN_JNI.java': 1356 'HashedSampleForAnnotationProcessorGenJni.2.golden', 1357 'J/N.java': 'HashedSampleForAnnotationProcessorGenJni.golden', 1358 'org/chromium/base/natives/module_GEN_JNI.java': 'ModuleGenJni.golden', 1359 'J/module_N.java': 'ModuleJN.golden' 1360 } 1361 self._TestEndToEndRegistration(input_java_files, options, name_to_goldens) 1362 1363 def testProxyNativesWithNatives(self): 1364 test_data = """ 1365 package org.chromium.foo; 1366 1367 class Foo { 1368 1369 @NativeMethods 1370 interface Natives { 1371 void foo(); 1372 String bar(String s, int y, char x, short z); 1373 String[] foobar(String[] a); 1374 void baz(long nativePtr, BazClass caller); 1375 void fooBar(long nativePtr); 1376 } 1377 1378 void justARegularFunction(); 1379 1380 native void nativeInstanceMethod(long nativeInstance); 1381 static native void nativeStaticMethod(); 1382 1383 } 1384 """ 1385 options_with_tracing = JniGeneratorOptions() 1386 jni_from_java = jni_generator.JNIFromJavaSource( 1387 test_data, 'org/chromium/foo/Foo', options_with_tracing) 1388 self.AssertGoldenTextEquals(jni_from_java.GetContent()) 1389 1390 def testEscapingProxyNatives(self): 1391 test_data = """ 1392 class SampleProxyJni { 1393 @NativeMethods 1394 interface Natives { 1395 void foo_bar(); 1396 void foo__bar(); 1397 } 1398 } 1399 """ 1400 qualified_clazz = 'org/chromium/example/SampleProxyJni' 1401 1402 natives, _ = jni_generator.ProxyHelpers.ExtractStaticProxyNatives( 1403 qualified_clazz, test_data, 'long') 1404 1405 golden_natives = [ 1406 NativeMethod( 1407 return_type='void', 1408 static=True, 1409 name='foo_bar', 1410 params=[], 1411 java_class_name=None, 1412 is_proxy=True, 1413 proxy_name='org_chromium_example_SampleProxyJni_foo_1bar'), 1414 NativeMethod( 1415 return_type='void', 1416 static=True, 1417 name='foo__bar', 1418 params=[], 1419 java_class_name=None, 1420 is_proxy=True, 1421 proxy_name='org_chromium_example_SampleProxyJni_foo_1_1bar'), 1422 ] 1423 1424 self.AssertListEquals(_RemoveHashedNames(natives), golden_natives) 1425 1426 def testForTestingKept(self): 1427 test_data = """ 1428 class SampleProxyJni { 1429 @NativeMethods 1430 interface Natives { 1431 void fooForTesting(); 1432 void fooForTest(); 1433 } 1434 } 1435 """ 1436 qualified_clazz = 'org/chromium/example/SampleProxyJni' 1437 1438 natives, _ = jni_generator.ProxyHelpers.ExtractStaticProxyNatives( 1439 qualified_clazz, test_data, 'long', True) 1440 1441 golden_natives = [ 1442 NativeMethod( 1443 return_type='void', 1444 static=True, 1445 name='fooForTesting', 1446 params=[], 1447 java_class_name=None, 1448 is_proxy=True, 1449 proxy_name='org_chromium_example_SampleProxyJni_fooForTesting'), 1450 NativeMethod( 1451 return_type='void', 1452 static=True, 1453 name='fooForTest', 1454 params=[], 1455 java_class_name=None, 1456 is_proxy=True, 1457 proxy_name='org_chromium_example_SampleProxyJni_fooForTest'), 1458 ] 1459 1460 self.AssertListEquals(_RemoveHashedNames(natives), golden_natives) 1461 1462 def testForTestingRemoved(self): 1463 test_data = """ 1464 class SampleProxyJni { 1465 @NativeMethods 1466 interface Natives { 1467 void fooForTesting(); 1468 void fooForTest(); 1469 } 1470 } 1471 """ 1472 qualified_clazz = 'org/chromium/example/SampleProxyJni' 1473 1474 natives, _ = jni_generator.ProxyHelpers.ExtractStaticProxyNatives( 1475 qualified_clazz, test_data, 'long', False) 1476 1477 self.AssertListEquals(_RemoveHashedNames(natives), []) 1478 1479 def testProxyNatives(self): 1480 test_data = """ 1481 class SampleProxyJni { 1482 private void do_not_match(); 1483 @VisibleForTesting 1484 @NativeMethods 1485 @Generated("Test") 1486 interface Natives { 1487 @NativeClassQualifiedName("FooAndroid::BarDelegate") 1488 void foo(long nativePtr); 1489 int bar(int x, int y); 1490 String foobar(String x, String y); 1491 } 1492 void dontmatchme(); 1493 public static void metoo(); 1494 public static native void this_is_a_non_proxy_native(); 1495 } 1496 """ 1497 1498 bad_spaced_test_data = """ 1499 class SampleProxyJni{ 1500 @NativeMethods interface 1501 Natives 1502 1503 1504 { @NativeClassQualifiedName("FooAndroid::BarDelegate") void 1505 foo(long nativePtr); 1506 int bar(int 1507 x, int y); String 1508 foobar(String x, String y); 1509 } 1510 1511 } 1512 """ 1513 1514 qualified_clazz = 'org/chromium/example/SampleProxyJni' 1515 1516 natives, _ = jni_generator.ProxyHelpers.ExtractStaticProxyNatives( 1517 qualified_clazz, test_data, 'long') 1518 bad_spacing_natives, _ = jni_generator.ProxyHelpers \ 1519 .ExtractStaticProxyNatives(qualified_clazz, bad_spaced_test_data, 'long') 1520 golden_natives = [ 1521 NativeMethod( 1522 return_type='void', 1523 static=True, 1524 name='foo', 1525 native_class_name='FooAndroid::BarDelegate', 1526 params=[Param(datatype='long', name='nativePtr')], 1527 java_class_name=None, 1528 is_proxy=True, 1529 proxy_name='org_chromium_example_SampleProxyJni_foo', 1530 ptr_type='long'), 1531 NativeMethod( 1532 return_type='int', 1533 static=True, 1534 name='bar', 1535 params=[ 1536 Param(datatype='int', name='x'), 1537 Param(datatype='int', name='y') 1538 ], 1539 java_class_name=None, 1540 is_proxy=True, 1541 proxy_name='org_chromium_example_SampleProxyJni_bar'), 1542 NativeMethod( 1543 return_type='String', 1544 static=True, 1545 name='foobar', 1546 params=[ 1547 Param(datatype='String', name='x'), 1548 Param(datatype='String', name='y') 1549 ], 1550 java_class_name=None, 1551 is_proxy=True, 1552 proxy_name='org_chromium_example_SampleProxyJni_foobar'), 1553 ] 1554 self.AssertListEquals(golden_natives, _RemoveHashedNames(natives)) 1555 self.AssertListEquals(golden_natives, 1556 _RemoveHashedNames(bad_spacing_natives)) 1557 options = JniGeneratorOptions() 1558 reg_options = JniRegistrationGeneratorOptions() 1559 reg_options.manual_jni_registration = True 1560 1561 jni_params = jni_generator.JniParams(qualified_clazz) 1562 h1 = jni_generator.InlHeaderFileGenerator('', '', qualified_clazz, natives, 1563 [], [], jni_params, options) 1564 self.AssertGoldenTextEquals(h1.GetContent()) 1565 h2 = jni_registration_generator.DictionaryGenerator(reg_options, '', '', 1566 qualified_clazz, 1567 natives, jni_params) 1568 content = TestGenerator._MergeRegistrationForTests([h2.Generate()]) 1569 1570 1571 self.AssertGoldenTextEquals( 1572 jni_registration_generator.CreateProxyJavaFromDict( 1573 reg_options, '', content), 1574 suffix='Java') 1575 1576 self.AssertGoldenTextEquals(jni_registration_generator.CreateFromDict( 1577 reg_options, '', content), 1578 suffix='Registrations') 1579 1580 def testProxyHashedExample(self): 1581 opts = JniGeneratorOptions() 1582 opts.use_proxy_hash = True 1583 path = os.path.join(_JAVA_SRC_DIR, 'SampleForAnnotationProcessor.java') 1584 1585 generated_text = self._CreateJniHeaderFromFile( 1586 path, 'org/chromium/example/jni_generator/SampleForAnnotationProcessor', 1587 opts) 1588 self.AssertGoldenTextEquals( 1589 generated_text, 1590 golden_file='HashedSampleForAnnotationProcessor_jni.golden') 1591 1592 def testProxyJniExample(self): 1593 generated_text = self._CreateJniHeaderFromFile( 1594 os.path.join(_JAVA_SRC_DIR, 'SampleForAnnotationProcessor.java'), 1595 'org/chromium/example/jni_generator/SampleForAnnotationProcessor') 1596 self.AssertGoldenTextEquals( 1597 generated_text, golden_file='SampleForAnnotationProcessor_jni.golden') 1598 1599 def testGenJniFlags(self): 1600 options = JniRegistrationGeneratorOptions() 1601 reg_dict = self._BuildRegDictFromSample() 1602 content = jni_registration_generator.CreateProxyJavaFromDict( 1603 options, '', reg_dict) 1604 self.AssertGoldenTextEquals(content, 'Disabled') 1605 1606 options.enable_proxy_mocks = True 1607 content = jni_registration_generator.CreateProxyJavaFromDict( 1608 options, '', reg_dict) 1609 self.AssertGoldenTextEquals(content, 'MocksEnabled') 1610 1611 options.require_mocks = True 1612 content = jni_registration_generator.CreateProxyJavaFromDict( 1613 options, '', reg_dict) 1614 self.AssertGoldenTextEquals(content, 'MocksRequired') 1615 1616 def testProxyTypeInfoPreserved(self): 1617 test_data = """ 1618 package org.chromium.foo; 1619 1620 class Foo { 1621 1622 @NativeMethods 1623 interface Natives { 1624 char[][] fooProxy(byte[][] b); 1625 SomeJavaType[][] barProxy(String[][] s, short z); 1626 String[] foobarProxy(String[] a, int[][] b); 1627 byte[][] bazProxy(long nativePtr, BazClass caller, 1628 SomeJavaType[][] someObjects); 1629 } 1630 """ 1631 natives, _ = ProxyHelpers.ExtractStaticProxyNatives( 1632 'org/chromium/foo/FooJni', test_data, 'long') 1633 golden_natives = [ 1634 NativeMethod( 1635 static=True, 1636 java_class_name=None, 1637 return_type='char[][]', 1638 name='fooProxy', 1639 params=[Param(datatype='byte[][]', name='b')], 1640 is_proxy=True, 1641 proxy_name='org_chromium_foo_FooJni_fooProxy'), 1642 NativeMethod( 1643 static=True, 1644 java_class_name=None, 1645 return_type='Object[][]', 1646 name='barProxy', 1647 params=[ 1648 Param(datatype='String[][]', name='s'), 1649 Param(datatype='short', name='z') 1650 ], 1651 is_proxy=True, 1652 proxy_name='org_chromium_foo_FooJni_barProxy'), 1653 NativeMethod( 1654 static=True, 1655 java_class_name=None, 1656 return_type='String[]', 1657 name='foobarProxy', 1658 params=[ 1659 Param(datatype='String[]', name='a'), 1660 Param(datatype='int[][]', name='b') 1661 ], 1662 is_proxy=True, 1663 proxy_name='org_chromium_foo_FooJni_foobarProxy'), 1664 NativeMethod( 1665 static=True, 1666 java_class_name=None, 1667 return_type='byte[][]', 1668 name='bazProxy', 1669 params=[ 1670 Param(datatype='long', name='nativePtr'), 1671 Param(datatype='Object', name='caller'), 1672 Param(datatype='Object[][]', name='someObjects') 1673 ], 1674 is_proxy=True, 1675 proxy_name='org_chromium_foo_FooJni_bazProxy', 1676 ptr_type='long') 1677 ] 1678 self.AssertListEquals(golden_natives, _RemoveHashedNames(natives)) 1679 1680 1681@unittest.skipIf(os.name == 'nt', 'Not intended to work on Windows') 1682class PackagePrefixTestGenerator(BaseTest): 1683 def testJniSelfDocumentingExampleWithPackagePrefix(self): 1684 options = JniGeneratorOptions() 1685 options.package_prefix = 'this.is.a.package.prefix' 1686 generated_text = self._CreateJniHeaderFromFile( 1687 os.path.join(_JAVA_SRC_DIR, 'SampleForTests.java'), 1688 'org/chromium/example/jni_generator/SampleForTests', options) 1689 self.AssertGoldenTextEquals( 1690 generated_text, 1691 golden_file='SampleForTestsWithPackagePrefix_jni.golden') 1692 1693 def testProxyPackagePrefixWithManualRegistration(self): 1694 input_java_files = ['SampleForAnnotationProcessor.java'] 1695 options = JniRegistrationGeneratorOptions() 1696 options.package_prefix = 'this.is.a.package.prefix' 1697 options.manual_jni_registration = True 1698 name_to_goldens = { 1699 'this/is/a/package/prefix/org/chromium/base/natives/GEN_JNI.java': 1700 'testProxyPackagePrefixWithManualRegistration.2.golden', 1701 } 1702 self._TestEndToEndRegistration( 1703 input_java_files, options, name_to_goldens, 1704 'testProxyPackagePrefixWithManualRegistrationHeader.golden') 1705 1706 def testProxyPackagePrefixWithProxyHash(self): 1707 input_java_files = ['SampleForAnnotationProcessor.java'] 1708 options = JniRegistrationGeneratorOptions() 1709 options.package_prefix = 'this.is.a.package.prefix' 1710 options.use_proxy_hash = True 1711 name_to_goldens = { 1712 'this/is/a/package/prefix/org/chromium/base/natives/GEN_JNI.java': 1713 'testProxyPackagePrefixWithProxyHash.2.golden', 1714 'this/is/a/package/prefix/J/N.java': 1715 'testProxyPackagePrefixWithProxyHash.golden', 1716 } 1717 self._TestEndToEndRegistration( 1718 input_java_files, options, name_to_goldens, 1719 'testProxyPackagePrefixWithProxyHashHeader.golden') 1720 1721 def testProxyPackagePrefixWithManualRegistrationWithProxyHash(self): 1722 input_java_files = ['SampleForAnnotationProcessor.java'] 1723 options = JniRegistrationGeneratorOptions() 1724 options.package_prefix = 'this.is.a.package.prefix' 1725 options.manual_jni_registration = True 1726 options.use_proxy_hash = True 1727 name_to_goldens = { 1728 'this/is/a/package/prefix/org/chromium/base/natives/GEN_JNI.java': 1729 'testProxyPackagePrefixWithManualRegistrationProxyHash.2.golden', 1730 'this/is/a/package/prefix/J/N.java': 1731 'testProxyPackagePrefixWithManualRegistrationProxyHash.golden', 1732 } 1733 self._TestEndToEndRegistration( 1734 input_java_files, options, name_to_goldens, 1735 'testProxyPackagePrefixWithManualRegistrationProxyHashHeader.golden') 1736 1737 1738@unittest.skipIf(os.name == 'nt', 'Not intended to work on Windows') 1739class MultiplexTestGenerator(BaseTest): 1740 options = JniRegistrationGeneratorOptions() 1741 options.enable_jni_multiplexing = True 1742 1743 def testProxyMultiplexGenJni(self): 1744 path = os.path.join(_JAVA_SRC_DIR, 'SampleForAnnotationProcessor.java') 1745 reg_dict = jni_registration_generator._DictForPath( 1746 self.options, self._JoinScriptDir(path)) 1747 reg_dict = self._MergeRegistrationForTests([reg_dict], 1748 enable_jni_multiplexing=True) 1749 1750 self.AssertGoldenTextEquals( 1751 jni_registration_generator.CreateProxyJavaFromDict( 1752 self.options, '', reg_dict), 1753 golden_file='testProxyMultiplexGenJni.golden') 1754 1755 self.AssertGoldenTextEquals( 1756 jni_registration_generator.CreateProxyJavaFromDict(self.options, 1757 '', 1758 reg_dict, 1759 forwarding=True), 1760 golden_file='testProxyMultiplexGenJni.2.golden') 1761 1762 def testProxyMultiplexNatives(self): 1763 path = os.path.join(_JAVA_SRC_DIR, 'SampleForAnnotationProcessor.java') 1764 reg_dict = jni_registration_generator._DictForPath( 1765 self.options, self._JoinScriptDir(path)) 1766 reg_dict = self._MergeRegistrationForTests([reg_dict], 1767 enable_jni_multiplexing=True) 1768 1769 self.AssertGoldenTextEquals(jni_registration_generator.CreateFromDict( 1770 self.options, '', reg_dict), 1771 golden_file='testProxyMultiplexNatives.golden') 1772 1773 def testProxyMultiplexNativesRegistration(self): 1774 path = os.path.join(_JAVA_SRC_DIR, 'SampleForAnnotationProcessor.java') 1775 reg_dict_for_registration = jni_registration_generator._DictForPath( 1776 self.options, self._JoinScriptDir(path)) 1777 reg_dict_for_registration = self._MergeRegistrationForTests( 1778 [reg_dict_for_registration], enable_jni_multiplexing=True) 1779 1780 new_options = copy.copy(self.options) 1781 new_options.manual_jni_registration = True 1782 self.AssertGoldenTextEquals( 1783 jni_registration_generator.CreateFromDict(new_options, '', 1784 reg_dict_for_registration), 1785 golden_file='testProxyMultiplexNativesRegistration.golden') 1786 1787 1788def TouchStamp(stamp_path): 1789 dir_name = os.path.dirname(stamp_path) 1790 if not os.path.isdir(dir_name): 1791 os.makedirs(dir_name) 1792 1793 with open(stamp_path, 'a'): 1794 os.utime(stamp_path, None) 1795 1796 1797def main(argv): 1798 parser = optparse.OptionParser() 1799 parser.add_option('--stamp', help='Path to touch on success.') 1800 parser.add_option( 1801 '-v', '--verbose', action='store_true', help='Whether to output details.') 1802 options, _ = parser.parse_args(argv[1:]) 1803 1804 test_result = unittest.main( 1805 argv=argv[0:1], exit=False, verbosity=(2 if options.verbose else 1)) 1806 1807 if test_result.result.wasSuccessful() and options.stamp: 1808 TouchStamp(options.stamp) 1809 1810 return not test_result.result.wasSuccessful() 1811 1812 1813if __name__ == '__main__': 1814 sys.exit(main(sys.argv)) 1815