1 #!/usr/bin/env python 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 8 This test suite contains various tests for the JNI generator. 9 It exercises the low-level parser all the way up to the 10 code generator and ensures the output matches a golden 11 file. 12 """ 13 14 import difflib 15 import inspect 16 import optparse 17 import os 18 import sys 19 import unittest 20 import jni_generator 21 from jni_generator import CalledByNative, JniParams, NativeMethod, Param 22 23 24 SCRIPT_NAME = 'base/android/jni_generator/jni_generator.py' 25 INCLUDES = ( 26 'base/android/jni_generator/jni_generator_helper.h' 27 ) 28 29 # Set this environment variable in order to regenerate the golden text 30 # files. 31 REBASELINE_ENV = 'REBASELINE' 32 33 class TestOptions(object): 34 """The mock options object which is passed to the jni_generator.py script.""" 35 36 def __init__(self): 37 self.namespace = None 38 self.script_name = SCRIPT_NAME 39 self.includes = INCLUDES 40 self.ptr_type = 'long' 41 self.cpp = 'cpp' 42 self.javap = 'javap' 43 self.native_exports = False 44 self.native_exports_optional = False 45 46 class TestGenerator(unittest.TestCase): 47 def assertObjEquals(self, first, second): 48 dict_first = first.__dict__ 49 dict_second = second.__dict__ 50 self.assertEquals(dict_first.keys(), dict_second.keys()) 51 for key, value in dict_first.iteritems(): 52 if (type(value) is list and len(value) and 53 isinstance(type(value[0]), object)): 54 self.assertListEquals(value, second.__getattribute__(key)) 55 else: 56 actual = second.__getattribute__(key) 57 self.assertEquals(value, actual, 58 'Key ' + key + ': ' + str(value) + '!=' + str(actual)) 59 60 def assertListEquals(self, first, second): 61 self.assertEquals(len(first), len(second)) 62 for i in xrange(len(first)): 63 if isinstance(first[i], object): 64 self.assertObjEquals(first[i], second[i]) 65 else: 66 self.assertEquals(first[i], second[i]) 67 68 def assertTextEquals(self, golden_text, generated_text): 69 if not self.compareText(golden_text, generated_text): 70 self.fail('Golden text mismatch.') 71 72 def compareText(self, golden_text, generated_text): 73 def FilterText(text): 74 return [ 75 l.strip() for l in text.split('\n') 76 if not l.startswith('// Copyright') 77 ] 78 stripped_golden = FilterText(golden_text) 79 stripped_generated = FilterText(generated_text) 80 if stripped_golden == stripped_generated: 81 return True 82 print self.id() 83 for line in difflib.context_diff(stripped_golden, stripped_generated): 84 print line 85 print '\n\nGenerated' 86 print '=' * 80 87 print generated_text 88 print '=' * 80 89 print 'Run with:' 90 print 'REBASELINE=1', sys.argv[0] 91 print 'to regenerate the data files.' 92 93 def _ReadGoldenFile(self, golden_file): 94 if not os.path.exists(golden_file): 95 return None 96 with file(golden_file, 'r') as f: 97 return f.read() 98 99 def assertGoldenTextEquals(self, generated_text): 100 script_dir = os.path.dirname(sys.argv[0]) 101 # This is the caller test method. 102 caller = inspect.stack()[1][3] 103 self.assertTrue(caller.startswith('test'), 104 'assertGoldenTextEquals can only be called from a ' 105 'test* method, not %s' % caller) 106 golden_file = os.path.join(script_dir, caller + '.golden') 107 golden_text = self._ReadGoldenFile(golden_file) 108 if os.environ.get(REBASELINE_ENV): 109 if golden_text != generated_text: 110 with file(golden_file, 'w') as f: 111 f.write(generated_text) 112 return 113 self.assertTextEquals(golden_text, generated_text) 114 115 def testInspectCaller(self): 116 def willRaise(): 117 # This function can only be called from a test* method. 118 self.assertGoldenTextEquals('') 119 self.assertRaises(AssertionError, willRaise) 120 121 def testNatives(self): 122 test_data = """" 123 interface OnFrameAvailableListener {} 124 private native int nativeInit(); 125 private native void nativeDestroy(int nativeChromeBrowserProvider); 126 private native long nativeAddBookmark( 127 int nativeChromeBrowserProvider, 128 String url, String title, boolean isFolder, long parentId); 129 private static native String nativeGetDomainAndRegistry(String url); 130 private static native void nativeCreateHistoricalTabFromState( 131 byte[] state, int tab_index); 132 private native byte[] nativeGetStateAsByteArray(View view); 133 private static native String[] nativeGetAutofillProfileGUIDs(); 134 private native void nativeSetRecognitionResults( 135 int sessionId, String[] results); 136 private native long nativeAddBookmarkFromAPI( 137 int nativeChromeBrowserProvider, 138 String url, Long created, Boolean isBookmark, 139 Long date, byte[] favicon, String title, Integer visits); 140 native int nativeFindAll(String find); 141 private static native OnFrameAvailableListener nativeGetInnerClass(); 142 private native Bitmap nativeQueryBitmap( 143 int nativeChromeBrowserProvider, 144 String[] projection, String selection, 145 String[] selectionArgs, String sortOrder); 146 private native void nativeGotOrientation( 147 int nativeDataFetcherImplAndroid, 148 double alpha, double beta, double gamma); 149 private static native Throwable nativeMessWithJavaException(Throwable e); 150 """ 151 jni_generator.JniParams.SetFullyQualifiedClass( 152 'org/chromium/example/jni_generator/SampleForTests') 153 jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data) 154 natives = jni_generator.ExtractNatives(test_data, 'int') 155 golden_natives = [ 156 NativeMethod(return_type='int', static=False, 157 name='Init', 158 params=[], 159 java_class_name=None, 160 type='function'), 161 NativeMethod(return_type='void', static=False, name='Destroy', 162 params=[Param(datatype='int', 163 name='nativeChromeBrowserProvider')], 164 java_class_name=None, 165 type='method', 166 p0_type='ChromeBrowserProvider'), 167 NativeMethod(return_type='long', static=False, name='AddBookmark', 168 params=[Param(datatype='int', 169 name='nativeChromeBrowserProvider'), 170 Param(datatype='String', 171 name='url'), 172 Param(datatype='String', 173 name='title'), 174 Param(datatype='boolean', 175 name='isFolder'), 176 Param(datatype='long', 177 name='parentId')], 178 java_class_name=None, 179 type='method', 180 p0_type='ChromeBrowserProvider'), 181 NativeMethod(return_type='String', static=True, 182 name='GetDomainAndRegistry', 183 params=[Param(datatype='String', 184 name='url')], 185 java_class_name=None, 186 type='function'), 187 NativeMethod(return_type='void', static=True, 188 name='CreateHistoricalTabFromState', 189 params=[Param(datatype='byte[]', 190 name='state'), 191 Param(datatype='int', 192 name='tab_index')], 193 java_class_name=None, 194 type='function'), 195 NativeMethod(return_type='byte[]', static=False, 196 name='GetStateAsByteArray', 197 params=[Param(datatype='View', name='view')], 198 java_class_name=None, 199 type='function'), 200 NativeMethod(return_type='String[]', static=True, 201 name='GetAutofillProfileGUIDs', params=[], 202 java_class_name=None, 203 type='function'), 204 NativeMethod(return_type='void', static=False, 205 name='SetRecognitionResults', 206 params=[Param(datatype='int', name='sessionId'), 207 Param(datatype='String[]', name='results')], 208 java_class_name=None, 209 type='function'), 210 NativeMethod(return_type='long', static=False, 211 name='AddBookmarkFromAPI', 212 params=[Param(datatype='int', 213 name='nativeChromeBrowserProvider'), 214 Param(datatype='String', 215 name='url'), 216 Param(datatype='Long', 217 name='created'), 218 Param(datatype='Boolean', 219 name='isBookmark'), 220 Param(datatype='Long', 221 name='date'), 222 Param(datatype='byte[]', 223 name='favicon'), 224 Param(datatype='String', 225 name='title'), 226 Param(datatype='Integer', 227 name='visits')], 228 java_class_name=None, 229 type='method', 230 p0_type='ChromeBrowserProvider'), 231 NativeMethod(return_type='int', static=False, 232 name='FindAll', 233 params=[Param(datatype='String', 234 name='find')], 235 java_class_name=None, 236 type='function'), 237 NativeMethod(return_type='OnFrameAvailableListener', static=True, 238 name='GetInnerClass', 239 params=[], 240 java_class_name=None, 241 type='function'), 242 NativeMethod(return_type='Bitmap', 243 static=False, 244 name='QueryBitmap', 245 params=[Param(datatype='int', 246 name='nativeChromeBrowserProvider'), 247 Param(datatype='String[]', 248 name='projection'), 249 Param(datatype='String', 250 name='selection'), 251 Param(datatype='String[]', 252 name='selectionArgs'), 253 Param(datatype='String', 254 name='sortOrder'), 255 ], 256 java_class_name=None, 257 type='method', 258 p0_type='ChromeBrowserProvider'), 259 NativeMethod(return_type='void', static=False, 260 name='GotOrientation', 261 params=[Param(datatype='int', 262 name='nativeDataFetcherImplAndroid'), 263 Param(datatype='double', 264 name='alpha'), 265 Param(datatype='double', 266 name='beta'), 267 Param(datatype='double', 268 name='gamma'), 269 ], 270 java_class_name=None, 271 type='method', 272 p0_type='content::DataFetcherImplAndroid'), 273 NativeMethod(return_type='Throwable', static=True, 274 name='MessWithJavaException', 275 params=[Param(datatype='Throwable', name='e')], 276 java_class_name=None, 277 type='function') 278 ] 279 self.assertListEquals(golden_natives, natives) 280 h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', 281 natives, [], [], TestOptions()) 282 self.assertGoldenTextEquals(h.GetContent()) 283 284 def testInnerClassNatives(self): 285 test_data = """ 286 class MyInnerClass { 287 @NativeCall("MyInnerClass") 288 private native int nativeInit(); 289 } 290 """ 291 natives = jni_generator.ExtractNatives(test_data, 'int') 292 golden_natives = [ 293 NativeMethod(return_type='int', static=False, 294 name='Init', params=[], 295 java_class_name='MyInnerClass', 296 type='function') 297 ] 298 self.assertListEquals(golden_natives, natives) 299 h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', 300 natives, [], [], TestOptions()) 301 self.assertGoldenTextEquals(h.GetContent()) 302 303 def testInnerClassNativesMultiple(self): 304 test_data = """ 305 class MyInnerClass { 306 @NativeCall("MyInnerClass") 307 private native int nativeInit(); 308 } 309 class MyOtherInnerClass { 310 @NativeCall("MyOtherInnerClass") 311 private native int nativeInit(); 312 } 313 """ 314 natives = jni_generator.ExtractNatives(test_data, 'int') 315 golden_natives = [ 316 NativeMethod(return_type='int', static=False, 317 name='Init', params=[], 318 java_class_name='MyInnerClass', 319 type='function'), 320 NativeMethod(return_type='int', static=False, 321 name='Init', params=[], 322 java_class_name='MyOtherInnerClass', 323 type='function') 324 ] 325 self.assertListEquals(golden_natives, natives) 326 h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', 327 natives, [], [], TestOptions()) 328 self.assertGoldenTextEquals(h.GetContent()) 329 330 def testInnerClassNativesBothInnerAndOuter(self): 331 test_data = """ 332 class MyOuterClass { 333 private native int nativeInit(); 334 class MyOtherInnerClass { 335 @NativeCall("MyOtherInnerClass") 336 private native int nativeInit(); 337 } 338 } 339 """ 340 natives = jni_generator.ExtractNatives(test_data, 'int') 341 golden_natives = [ 342 NativeMethod(return_type='int', static=False, 343 name='Init', params=[], 344 java_class_name=None, 345 type='function'), 346 NativeMethod(return_type='int', static=False, 347 name='Init', params=[], 348 java_class_name='MyOtherInnerClass', 349 type='function') 350 ] 351 self.assertListEquals(golden_natives, natives) 352 h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', 353 natives, [], [], TestOptions()) 354 self.assertGoldenTextEquals(h.GetContent()) 355 356 def testCalledByNatives(self): 357 test_data = """" 358 import android.graphics.Bitmap; 359 import android.view.View; 360 import java.io.InputStream; 361 import java.util.List; 362 363 class InnerClass {} 364 365 @CalledByNative 366 InnerClass showConfirmInfoBar(int nativeInfoBar, 367 String buttonOk, String buttonCancel, String title, Bitmap icon) { 368 InfoBar infobar = new ConfirmInfoBar(nativeInfoBar, mContext, 369 buttonOk, buttonCancel, 370 title, icon); 371 return infobar; 372 } 373 @CalledByNative 374 InnerClass showAutoLoginInfoBar(int nativeInfoBar, 375 String realm, String account, String args) { 376 AutoLoginInfoBar infobar = new AutoLoginInfoBar(nativeInfoBar, mContext, 377 realm, account, args); 378 if (infobar.displayedAccountCount() == 0) 379 infobar = null; 380 return infobar; 381 } 382 @CalledByNative("InfoBar") 383 void dismiss(); 384 @SuppressWarnings("unused") 385 @CalledByNative 386 private static boolean shouldShowAutoLogin(View view, 387 String realm, String account, String args) { 388 AccountManagerContainer accountManagerContainer = 389 new AccountManagerContainer((Activity)contentView.getContext(), 390 realm, account, args); 391 String[] logins = accountManagerContainer.getAccountLogins(null); 392 return logins.length != 0; 393 } 394 @CalledByNative 395 static InputStream openUrl(String url) { 396 return null; 397 } 398 @CalledByNative 399 private void activateHardwareAcceleration(final boolean activated, 400 final int iPid, final int iType, 401 final int iPrimaryID, final int iSecondaryID) { 402 if (!activated) { 403 return 404 } 405 } 406 @CalledByNativeUnchecked 407 private void uncheckedCall(int iParam); 408 409 @CalledByNative 410 public byte[] returnByteArray(); 411 412 @CalledByNative 413 public boolean[] returnBooleanArray(); 414 415 @CalledByNative 416 public char[] returnCharArray(); 417 418 @CalledByNative 419 public short[] returnShortArray(); 420 421 @CalledByNative 422 public int[] returnIntArray(); 423 424 @CalledByNative 425 public long[] returnLongArray(); 426 427 @CalledByNative 428 public double[] returnDoubleArray(); 429 430 @CalledByNative 431 public Object[] returnObjectArray(); 432 433 @CalledByNative 434 public byte[][] returnArrayOfByteArray(); 435 436 @CalledByNative 437 public Bitmap.CompressFormat getCompressFormat(); 438 439 @CalledByNative 440 public List<Bitmap.CompressFormat> getCompressFormatList(); 441 """ 442 jni_generator.JniParams.SetFullyQualifiedClass('org/chromium/Foo') 443 jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data) 444 called_by_natives = jni_generator.ExtractCalledByNatives(test_data) 445 golden_called_by_natives = [ 446 CalledByNative( 447 return_type='InnerClass', 448 system_class=False, 449 static=False, 450 name='showConfirmInfoBar', 451 method_id_var_name='showConfirmInfoBar', 452 java_class_name='', 453 params=[Param(datatype='int', name='nativeInfoBar'), 454 Param(datatype='String', name='buttonOk'), 455 Param(datatype='String', name='buttonCancel'), 456 Param(datatype='String', name='title'), 457 Param(datatype='Bitmap', name='icon')], 458 env_call=('Object', ''), 459 unchecked=False, 460 ), 461 CalledByNative( 462 return_type='InnerClass', 463 system_class=False, 464 static=False, 465 name='showAutoLoginInfoBar', 466 method_id_var_name='showAutoLoginInfoBar', 467 java_class_name='', 468 params=[Param(datatype='int', name='nativeInfoBar'), 469 Param(datatype='String', name='realm'), 470 Param(datatype='String', name='account'), 471 Param(datatype='String', name='args')], 472 env_call=('Object', ''), 473 unchecked=False, 474 ), 475 CalledByNative( 476 return_type='void', 477 system_class=False, 478 static=False, 479 name='dismiss', 480 method_id_var_name='dismiss', 481 java_class_name='InfoBar', 482 params=[], 483 env_call=('Void', ''), 484 unchecked=False, 485 ), 486 CalledByNative( 487 return_type='boolean', 488 system_class=False, 489 static=True, 490 name='shouldShowAutoLogin', 491 method_id_var_name='shouldShowAutoLogin', 492 java_class_name='', 493 params=[Param(datatype='View', name='view'), 494 Param(datatype='String', name='realm'), 495 Param(datatype='String', name='account'), 496 Param(datatype='String', name='args')], 497 env_call=('Boolean', ''), 498 unchecked=False, 499 ), 500 CalledByNative( 501 return_type='InputStream', 502 system_class=False, 503 static=True, 504 name='openUrl', 505 method_id_var_name='openUrl', 506 java_class_name='', 507 params=[Param(datatype='String', name='url')], 508 env_call=('Object', ''), 509 unchecked=False, 510 ), 511 CalledByNative( 512 return_type='void', 513 system_class=False, 514 static=False, 515 name='activateHardwareAcceleration', 516 method_id_var_name='activateHardwareAcceleration', 517 java_class_name='', 518 params=[Param(datatype='boolean', name='activated'), 519 Param(datatype='int', name='iPid'), 520 Param(datatype='int', name='iType'), 521 Param(datatype='int', name='iPrimaryID'), 522 Param(datatype='int', name='iSecondaryID'), 523 ], 524 env_call=('Void', ''), 525 unchecked=False, 526 ), 527 CalledByNative( 528 return_type='void', 529 system_class=False, 530 static=False, 531 name='uncheckedCall', 532 method_id_var_name='uncheckedCall', 533 java_class_name='', 534 params=[Param(datatype='int', name='iParam')], 535 env_call=('Void', ''), 536 unchecked=True, 537 ), 538 CalledByNative( 539 return_type='byte[]', 540 system_class=False, 541 static=False, 542 name='returnByteArray', 543 method_id_var_name='returnByteArray', 544 java_class_name='', 545 params=[], 546 env_call=('Void', ''), 547 unchecked=False, 548 ), 549 CalledByNative( 550 return_type='boolean[]', 551 system_class=False, 552 static=False, 553 name='returnBooleanArray', 554 method_id_var_name='returnBooleanArray', 555 java_class_name='', 556 params=[], 557 env_call=('Void', ''), 558 unchecked=False, 559 ), 560 CalledByNative( 561 return_type='char[]', 562 system_class=False, 563 static=False, 564 name='returnCharArray', 565 method_id_var_name='returnCharArray', 566 java_class_name='', 567 params=[], 568 env_call=('Void', ''), 569 unchecked=False, 570 ), 571 CalledByNative( 572 return_type='short[]', 573 system_class=False, 574 static=False, 575 name='returnShortArray', 576 method_id_var_name='returnShortArray', 577 java_class_name='', 578 params=[], 579 env_call=('Void', ''), 580 unchecked=False, 581 ), 582 CalledByNative( 583 return_type='int[]', 584 system_class=False, 585 static=False, 586 name='returnIntArray', 587 method_id_var_name='returnIntArray', 588 java_class_name='', 589 params=[], 590 env_call=('Void', ''), 591 unchecked=False, 592 ), 593 CalledByNative( 594 return_type='long[]', 595 system_class=False, 596 static=False, 597 name='returnLongArray', 598 method_id_var_name='returnLongArray', 599 java_class_name='', 600 params=[], 601 env_call=('Void', ''), 602 unchecked=False, 603 ), 604 CalledByNative( 605 return_type='double[]', 606 system_class=False, 607 static=False, 608 name='returnDoubleArray', 609 method_id_var_name='returnDoubleArray', 610 java_class_name='', 611 params=[], 612 env_call=('Void', ''), 613 unchecked=False, 614 ), 615 CalledByNative( 616 return_type='Object[]', 617 system_class=False, 618 static=False, 619 name='returnObjectArray', 620 method_id_var_name='returnObjectArray', 621 java_class_name='', 622 params=[], 623 env_call=('Void', ''), 624 unchecked=False, 625 ), 626 CalledByNative( 627 return_type='byte[][]', 628 system_class=False, 629 static=False, 630 name='returnArrayOfByteArray', 631 method_id_var_name='returnArrayOfByteArray', 632 java_class_name='', 633 params=[], 634 env_call=('Void', ''), 635 unchecked=False, 636 ), 637 CalledByNative( 638 return_type='Bitmap.CompressFormat', 639 system_class=False, 640 static=False, 641 name='getCompressFormat', 642 method_id_var_name='getCompressFormat', 643 java_class_name='', 644 params=[], 645 env_call=('Void', ''), 646 unchecked=False, 647 ), 648 CalledByNative( 649 return_type='List<Bitmap.CompressFormat>', 650 system_class=False, 651 static=False, 652 name='getCompressFormatList', 653 method_id_var_name='getCompressFormatList', 654 java_class_name='', 655 params=[], 656 env_call=('Void', ''), 657 unchecked=False, 658 ), 659 ] 660 self.assertListEquals(golden_called_by_natives, called_by_natives) 661 h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', 662 [], called_by_natives, [], 663 TestOptions()) 664 self.assertGoldenTextEquals(h.GetContent()) 665 666 def testCalledByNativeParseError(self): 667 try: 668 jni_generator.ExtractCalledByNatives(""" 669 @CalledByNative 670 public static int foo(); // This one is fine 671 672 @CalledByNative 673 scooby doo 674 """) 675 self.fail('Expected a ParseError') 676 except jni_generator.ParseError, e: 677 self.assertEquals(('@CalledByNative', 'scooby doo'), e.context_lines) 678 679 def testFullyQualifiedClassName(self): 680 contents = """ 681 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 682 // Use of this source code is governed by a BSD-style license that can be 683 // found in the LICENSE file. 684 685 package org.chromium.content.browser; 686 687 import org.chromium.base.BuildInfo; 688 """ 689 self.assertEquals('org/chromium/content/browser/Foo', 690 jni_generator.ExtractFullyQualifiedJavaClassName( 691 'org/chromium/content/browser/Foo.java', contents)) 692 self.assertEquals('org/chromium/content/browser/Foo', 693 jni_generator.ExtractFullyQualifiedJavaClassName( 694 'frameworks/Foo.java', contents)) 695 self.assertRaises(SyntaxError, 696 jni_generator.ExtractFullyQualifiedJavaClassName, 697 'com/foo/Bar', 'no PACKAGE line') 698 699 def testMethodNameMangling(self): 700 self.assertEquals('closeV', 701 jni_generator.GetMangledMethodName('close', [], 'void')) 702 self.assertEquals('readI_AB_I_I', 703 jni_generator.GetMangledMethodName('read', 704 [Param(name='p1', 705 datatype='byte[]'), 706 Param(name='p2', 707 datatype='int'), 708 Param(name='p3', 709 datatype='int'),], 710 'int')) 711 self.assertEquals('openJIIS_JLS', 712 jni_generator.GetMangledMethodName('open', 713 [Param(name='p1', 714 datatype='java/lang/String'),], 715 'java/io/InputStream')) 716 717 def testFromJavaPGenerics(self): 718 contents = """ 719 public abstract class java.util.HashSet<T> extends java.util.AbstractSet<E> 720 implements java.util.Set<E>, java.lang.Cloneable, java.io.Serializable { 721 public void dummy(); 722 Signature: ()V 723 } 724 """ 725 jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'), 726 TestOptions()) 727 self.assertEquals(1, len(jni_from_javap.called_by_natives)) 728 self.assertGoldenTextEquals(jni_from_javap.GetContent()) 729 730 def testSnippnetJavap6_7_8(self): 731 content_javap6 = """ 732 public class java.util.HashSet { 733 public boolean add(java.lang.Object); 734 Signature: (Ljava/lang/Object;)Z 735 } 736 """ 737 738 content_javap7 = """ 739 public class java.util.HashSet { 740 public boolean add(E); 741 Signature: (Ljava/lang/Object;)Z 742 } 743 """ 744 745 content_javap8 = """ 746 public class java.util.HashSet { 747 public boolean add(E); 748 descriptor: (Ljava/lang/Object;)Z 749 } 750 """ 751 752 jni_from_javap6 = jni_generator.JNIFromJavaP(content_javap6.split('\n'), 753 TestOptions()) 754 jni_from_javap7 = jni_generator.JNIFromJavaP(content_javap7.split('\n'), 755 TestOptions()) 756 jni_from_javap8 = jni_generator.JNIFromJavaP(content_javap8.split('\n'), 757 TestOptions()) 758 self.assertTrue(jni_from_javap6.GetContent()) 759 self.assertTrue(jni_from_javap7.GetContent()) 760 self.assertTrue(jni_from_javap8.GetContent()) 761 # Ensure the javap7 is correctly parsed and uses the Signature field rather 762 # than the "E" parameter. 763 self.assertTextEquals(jni_from_javap6.GetContent(), 764 jni_from_javap7.GetContent()) 765 # Ensure the javap8 is correctly parsed and uses the descriptor field. 766 self.assertTextEquals(jni_from_javap7.GetContent(), 767 jni_from_javap8.GetContent()) 768 769 def testFromJavaP(self): 770 contents = self._ReadGoldenFile(os.path.join(os.path.dirname(sys.argv[0]), 771 'testInputStream.javap')) 772 jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'), 773 TestOptions()) 774 self.assertEquals(10, len(jni_from_javap.called_by_natives)) 775 self.assertGoldenTextEquals(jni_from_javap.GetContent()) 776 777 def testConstantsFromJavaP(self): 778 for f in ['testMotionEvent.javap', 'testMotionEvent.javap7']: 779 contents = self._ReadGoldenFile(os.path.join(os.path.dirname(sys.argv[0]), 780 f)) 781 jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'), 782 TestOptions()) 783 self.assertEquals(86, len(jni_from_javap.called_by_natives)) 784 self.assertGoldenTextEquals(jni_from_javap.GetContent()) 785 786 def testREForNatives(self): 787 # We should not match "native SyncSetupFlow" inside the comment. 788 test_data = """ 789 /** 790 * Invoked when the setup process is complete so we can disconnect from the 791 * native-side SyncSetupFlowHandler. 792 */ 793 public void destroy() { 794 Log.v(TAG, "Destroying native SyncSetupFlow"); 795 if (mNativeSyncSetupFlow != 0) { 796 nativeSyncSetupEnded(mNativeSyncSetupFlow); 797 mNativeSyncSetupFlow = 0; 798 } 799 } 800 private native void nativeSyncSetupEnded( 801 int nativeAndroidSyncSetupFlowHandler); 802 """ 803 jni_from_java = jni_generator.JNIFromJavaSource( 804 test_data, 'foo/bar', TestOptions()) 805 806 def testRaisesOnNonJNIMethod(self): 807 test_data = """ 808 class MyInnerClass { 809 private int Foo(int p0) { 810 } 811 } 812 """ 813 self.assertRaises(SyntaxError, 814 jni_generator.JNIFromJavaSource, 815 test_data, 'foo/bar', TestOptions()) 816 817 def testJniSelfDocumentingExample(self): 818 script_dir = os.path.dirname(sys.argv[0]) 819 content = file(os.path.join(script_dir, 820 'java/src/org/chromium/example/jni_generator/SampleForTests.java') 821 ).read() 822 golden_file = os.path.join(script_dir, 'golden_sample_for_tests_jni.h') 823 golden_content = file(golden_file).read() 824 jni_from_java = jni_generator.JNIFromJavaSource( 825 content, 'org/chromium/example/jni_generator/SampleForTests', 826 TestOptions()) 827 generated_text = jni_from_java.GetContent() 828 if not self.compareText(golden_content, generated_text): 829 if os.environ.get(REBASELINE_ENV): 830 with file(golden_file, 'w') as f: 831 f.write(generated_text) 832 return 833 self.fail('testJniSelfDocumentingExample') 834 835 def testNoWrappingPreprocessorLines(self): 836 test_data = """ 837 package com.google.lookhowextremelylongiam.snarf.icankeepthisupallday; 838 839 class ReallyLongClassNamesAreAllTheRage { 840 private static native int nativeTest(); 841 } 842 """ 843 jni_from_java = jni_generator.JNIFromJavaSource( 844 test_data, ('com/google/lookhowextremelylongiam/snarf/' 845 'icankeepthisupallday/ReallyLongClassNamesAreAllTheRage'), 846 TestOptions()) 847 jni_lines = jni_from_java.GetContent().split('\n') 848 line = filter(lambda line: line.lstrip().startswith('#ifndef'), 849 jni_lines)[0] 850 self.assertTrue(len(line) > 80, 851 ('Expected #ifndef line to be > 80 chars: ', line)) 852 853 def testImports(self): 854 import_header = """ 855 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 856 // Use of this source code is governed by a BSD-style license that can be 857 // found in the LICENSE file. 858 859 package org.chromium.content.app; 860 861 import android.app.Service; 862 import android.content.Context; 863 import android.content.Intent; 864 import android.graphics.SurfaceTexture; 865 import android.os.Bundle; 866 import android.os.IBinder; 867 import android.os.ParcelFileDescriptor; 868 import android.os.Process; 869 import android.os.RemoteException; 870 import android.util.Log; 871 import android.view.Surface; 872 873 import java.util.ArrayList; 874 875 import org.chromium.base.annotations.CalledByNative; 876 import org.chromium.base.annotations.JNINamespace; 877 import org.chromium.content.app.ContentMain; 878 import org.chromium.content.browser.SandboxedProcessConnection; 879 import org.chromium.content.common.ISandboxedProcessCallback; 880 import org.chromium.content.common.ISandboxedProcessService; 881 import org.chromium.content.common.WillNotRaise.AnException; 882 import org.chromium.content.common.WillRaise.AnException; 883 884 import static org.chromium.Bar.Zoo; 885 886 class Foo { 887 public static class BookmarkNode implements Parcelable { 888 } 889 public interface PasswordListObserver { 890 } 891 } 892 """ 893 jni_generator.JniParams.SetFullyQualifiedClass( 894 'org/chromium/content/app/Foo') 895 jni_generator.JniParams.ExtractImportsAndInnerClasses(import_header) 896 self.assertTrue('Lorg/chromium/content/common/ISandboxedProcessService' in 897 jni_generator.JniParams._imports) 898 self.assertTrue('Lorg/chromium/Bar/Zoo' in 899 jni_generator.JniParams._imports) 900 self.assertTrue('Lorg/chromium/content/app/Foo$BookmarkNode' in 901 jni_generator.JniParams._inner_classes) 902 self.assertTrue('Lorg/chromium/content/app/Foo$PasswordListObserver' in 903 jni_generator.JniParams._inner_classes) 904 self.assertEquals('Lorg/chromium/content/app/ContentMain$Inner;', 905 jni_generator.JniParams.JavaToJni('ContentMain.Inner')) 906 self.assertRaises(SyntaxError, 907 jni_generator.JniParams.JavaToJni, 908 'AnException') 909 910 def testJniParamsJavaToJni(self): 911 self.assertTextEquals('I', JniParams.JavaToJni('int')) 912 self.assertTextEquals('[B', JniParams.JavaToJni('byte[]')) 913 self.assertTextEquals( 914 '[Ljava/nio/ByteBuffer;', JniParams.JavaToJni('java/nio/ByteBuffer[]')) 915 916 def testNativesLong(self): 917 test_options = TestOptions() 918 test_options.ptr_type = 'long' 919 test_data = """" 920 private native void nativeDestroy(long nativeChromeBrowserProvider); 921 """ 922 jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data) 923 natives = jni_generator.ExtractNatives(test_data, test_options.ptr_type) 924 golden_natives = [ 925 NativeMethod(return_type='void', static=False, name='Destroy', 926 params=[Param(datatype='long', 927 name='nativeChromeBrowserProvider')], 928 java_class_name=None, 929 type='method', 930 p0_type='ChromeBrowserProvider', 931 ptr_type=test_options.ptr_type), 932 ] 933 self.assertListEquals(golden_natives, natives) 934 h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', 935 natives, [], [], test_options) 936 self.assertGoldenTextEquals(h.GetContent()) 937 938 def runNativeExportsOption(self, optional): 939 test_data = """ 940 package org.chromium.example.jni_generator; 941 942 /** The pointer to the native Test. */ 943 long nativeTest; 944 945 class Test { 946 private static native int nativeStaticMethod(long nativeTest, int arg1); 947 private native int nativeMethod(long nativeTest, int arg1); 948 @CalledByNative 949 private void testMethodWithParam(int iParam); 950 @CalledByNative 951 private String testMethodWithParamAndReturn(int iParam); 952 @CalledByNative 953 private static int testStaticMethodWithParam(int iParam); 954 @CalledByNative 955 private static double testMethodWithNoParam(); 956 @CalledByNative 957 private static String testStaticMethodWithNoParam(); 958 959 class MyInnerClass { 960 @NativeCall("MyInnerClass") 961 private native int nativeInit(); 962 } 963 class MyOtherInnerClass { 964 @NativeCall("MyOtherInnerClass") 965 private native int nativeInit(); 966 } 967 } 968 """ 969 options = TestOptions() 970 options.native_exports = True 971 options.native_exports_optional = optional 972 jni_from_java = jni_generator.JNIFromJavaSource( 973 test_data, 'org/chromium/example/jni_generator/SampleForTests', options) 974 return jni_from_java.GetContent() 975 976 def testNativeExportsOption(self): 977 content = self.runNativeExportsOption(False) 978 self.assertGoldenTextEquals(content) 979 980 def testNativeExportsOptionalOption(self): 981 content = self.runNativeExportsOption(True) 982 self.assertGoldenTextEquals(content) 983 984 def testOuterInnerRaises(self): 985 test_data = """ 986 package org.chromium.media; 987 988 @CalledByNative 989 static int getCaptureFormatWidth(VideoCapture.CaptureFormat format) { 990 return format.getWidth(); 991 } 992 """ 993 def willRaise(): 994 jni_generator.JNIFromJavaSource( 995 test_data, 996 'org/chromium/media/VideoCaptureFactory', 997 TestOptions()) 998 self.assertRaises(SyntaxError, willRaise) 999 1000 def testSingleJNIAdditionalImport(self): 1001 test_data = """ 1002 package org.chromium.foo; 1003 1004 @JNIAdditionalImport(Bar.class) 1005 class Foo { 1006 1007 @CalledByNative 1008 private static void calledByNative(Bar.Callback callback) { 1009 } 1010 1011 private static native void nativeDoSomething(Bar.Callback callback); 1012 } 1013 """ 1014 jni_from_java = jni_generator.JNIFromJavaSource(test_data, 1015 'org/chromium/foo/Foo', 1016 TestOptions()) 1017 self.assertGoldenTextEquals(jni_from_java.GetContent()) 1018 1019 def testMultipleJNIAdditionalImport(self): 1020 test_data = """ 1021 package org.chromium.foo; 1022 1023 @JNIAdditionalImport({Bar1.class, Bar2.class}) 1024 class Foo { 1025 1026 @CalledByNative 1027 private static void calledByNative(Bar1.Callback callback1, 1028 Bar2.Callback callback2) { 1029 } 1030 1031 private static native void nativeDoSomething(Bar1.Callback callback1, 1032 Bar2.Callback callback2); 1033 } 1034 """ 1035 jni_from_java = jni_generator.JNIFromJavaSource(test_data, 1036 'org/chromium/foo/Foo', 1037 TestOptions()) 1038 self.assertGoldenTextEquals(jni_from_java.GetContent()) 1039 1040 1041 def TouchStamp(stamp_path): 1042 dir_name = os.path.dirname(stamp_path) 1043 if not os.path.isdir(dir_name): 1044 os.makedirs() 1045 1046 with open(stamp_path, 'a'): 1047 os.utime(stamp_path, None) 1048 1049 1050 def main(argv): 1051 parser = optparse.OptionParser() 1052 parser.add_option('--stamp', help='Path to touch on success.') 1053 options, _ = parser.parse_args(argv[1:]) 1054 1055 test_result = unittest.main(argv=argv[0:1], exit=False) 1056 1057 if test_result.result.wasSuccessful() and options.stamp: 1058 TouchStamp(options.stamp) 1059 1060 return not test_result.result.wasSuccessful() 1061 1062 1063 if __name__ == '__main__': 1064 sys.exit(main(sys.argv)) 1065