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 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 difflib 15import inspect 16import optparse 17import os 18import sys 19import unittest 20import jni_generator 21from jni_generator import CalledByNative, JniParams, NativeMethod, Param 22 23 24SCRIPT_NAME = 'base/android/jni_generator/jni_generator.py' 25INCLUDES = ( 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. 31REBASELINE_ENV = 'REBASELINE' 32 33class 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_optional = True 44 self.enable_profiling = False 45 46class 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 @CalledByNative 407 public static @Status int updateStatus(@Status int status) { 408 return getAndUpdateStatus(status); 409 } 410 @CalledByNativeUnchecked 411 private void uncheckedCall(int iParam); 412 413 @CalledByNative 414 public byte[] returnByteArray(); 415 416 @CalledByNative 417 public boolean[] returnBooleanArray(); 418 419 @CalledByNative 420 public char[] returnCharArray(); 421 422 @CalledByNative 423 public short[] returnShortArray(); 424 425 @CalledByNative 426 public int[] returnIntArray(); 427 428 @CalledByNative 429 public long[] returnLongArray(); 430 431 @CalledByNative 432 public double[] returnDoubleArray(); 433 434 @CalledByNative 435 public Object[] returnObjectArray(); 436 437 @CalledByNative 438 public byte[][] returnArrayOfByteArray(); 439 440 @CalledByNative 441 public Bitmap.CompressFormat getCompressFormat(); 442 443 @CalledByNative 444 public List<Bitmap.CompressFormat> getCompressFormatList(); 445 """ 446 jni_generator.JniParams.SetFullyQualifiedClass('org/chromium/Foo') 447 jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data) 448 called_by_natives = jni_generator.ExtractCalledByNatives(test_data) 449 golden_called_by_natives = [ 450 CalledByNative( 451 return_type='InnerClass', 452 system_class=False, 453 static=False, 454 name='showConfirmInfoBar', 455 method_id_var_name='showConfirmInfoBar', 456 java_class_name='', 457 params=[Param(datatype='int', name='nativeInfoBar'), 458 Param(datatype='String', name='buttonOk'), 459 Param(datatype='String', name='buttonCancel'), 460 Param(datatype='String', name='title'), 461 Param(datatype='Bitmap', name='icon')], 462 env_call=('Object', ''), 463 unchecked=False, 464 ), 465 CalledByNative( 466 return_type='InnerClass', 467 system_class=False, 468 static=False, 469 name='showAutoLoginInfoBar', 470 method_id_var_name='showAutoLoginInfoBar', 471 java_class_name='', 472 params=[Param(datatype='int', name='nativeInfoBar'), 473 Param(datatype='String', name='realm'), 474 Param(datatype='String', name='account'), 475 Param(datatype='String', name='args')], 476 env_call=('Object', ''), 477 unchecked=False, 478 ), 479 CalledByNative( 480 return_type='void', 481 system_class=False, 482 static=False, 483 name='dismiss', 484 method_id_var_name='dismiss', 485 java_class_name='InfoBar', 486 params=[], 487 env_call=('Void', ''), 488 unchecked=False, 489 ), 490 CalledByNative( 491 return_type='boolean', 492 system_class=False, 493 static=True, 494 name='shouldShowAutoLogin', 495 method_id_var_name='shouldShowAutoLogin', 496 java_class_name='', 497 params=[Param(datatype='View', name='view'), 498 Param(datatype='String', name='realm'), 499 Param(datatype='String', name='account'), 500 Param(datatype='String', name='args')], 501 env_call=('Boolean', ''), 502 unchecked=False, 503 ), 504 CalledByNative( 505 return_type='InputStream', 506 system_class=False, 507 static=True, 508 name='openUrl', 509 method_id_var_name='openUrl', 510 java_class_name='', 511 params=[Param(datatype='String', name='url')], 512 env_call=('Object', ''), 513 unchecked=False, 514 ), 515 CalledByNative( 516 return_type='void', 517 system_class=False, 518 static=False, 519 name='activateHardwareAcceleration', 520 method_id_var_name='activateHardwareAcceleration', 521 java_class_name='', 522 params=[Param(datatype='boolean', name='activated'), 523 Param(datatype='int', name='iPid'), 524 Param(datatype='int', name='iType'), 525 Param(datatype='int', name='iPrimaryID'), 526 Param(datatype='int', name='iSecondaryID'), 527 ], 528 env_call=('Void', ''), 529 unchecked=False, 530 ), 531 CalledByNative( 532 return_type='int', 533 system_class=False, 534 static=True, 535 name='updateStatus', 536 method_id_var_name='updateStatus', 537 java_class_name='', 538 params=[Param(datatype='int', name='status')], 539 env_call=('Integer', ''), 540 unchecked=False, 541 ), 542 CalledByNative( 543 return_type='void', 544 system_class=False, 545 static=False, 546 name='uncheckedCall', 547 method_id_var_name='uncheckedCall', 548 java_class_name='', 549 params=[Param(datatype='int', name='iParam')], 550 env_call=('Void', ''), 551 unchecked=True, 552 ), 553 CalledByNative( 554 return_type='byte[]', 555 system_class=False, 556 static=False, 557 name='returnByteArray', 558 method_id_var_name='returnByteArray', 559 java_class_name='', 560 params=[], 561 env_call=('Void', ''), 562 unchecked=False, 563 ), 564 CalledByNative( 565 return_type='boolean[]', 566 system_class=False, 567 static=False, 568 name='returnBooleanArray', 569 method_id_var_name='returnBooleanArray', 570 java_class_name='', 571 params=[], 572 env_call=('Void', ''), 573 unchecked=False, 574 ), 575 CalledByNative( 576 return_type='char[]', 577 system_class=False, 578 static=False, 579 name='returnCharArray', 580 method_id_var_name='returnCharArray', 581 java_class_name='', 582 params=[], 583 env_call=('Void', ''), 584 unchecked=False, 585 ), 586 CalledByNative( 587 return_type='short[]', 588 system_class=False, 589 static=False, 590 name='returnShortArray', 591 method_id_var_name='returnShortArray', 592 java_class_name='', 593 params=[], 594 env_call=('Void', ''), 595 unchecked=False, 596 ), 597 CalledByNative( 598 return_type='int[]', 599 system_class=False, 600 static=False, 601 name='returnIntArray', 602 method_id_var_name='returnIntArray', 603 java_class_name='', 604 params=[], 605 env_call=('Void', ''), 606 unchecked=False, 607 ), 608 CalledByNative( 609 return_type='long[]', 610 system_class=False, 611 static=False, 612 name='returnLongArray', 613 method_id_var_name='returnLongArray', 614 java_class_name='', 615 params=[], 616 env_call=('Void', ''), 617 unchecked=False, 618 ), 619 CalledByNative( 620 return_type='double[]', 621 system_class=False, 622 static=False, 623 name='returnDoubleArray', 624 method_id_var_name='returnDoubleArray', 625 java_class_name='', 626 params=[], 627 env_call=('Void', ''), 628 unchecked=False, 629 ), 630 CalledByNative( 631 return_type='Object[]', 632 system_class=False, 633 static=False, 634 name='returnObjectArray', 635 method_id_var_name='returnObjectArray', 636 java_class_name='', 637 params=[], 638 env_call=('Void', ''), 639 unchecked=False, 640 ), 641 CalledByNative( 642 return_type='byte[][]', 643 system_class=False, 644 static=False, 645 name='returnArrayOfByteArray', 646 method_id_var_name='returnArrayOfByteArray', 647 java_class_name='', 648 params=[], 649 env_call=('Void', ''), 650 unchecked=False, 651 ), 652 CalledByNative( 653 return_type='Bitmap.CompressFormat', 654 system_class=False, 655 static=False, 656 name='getCompressFormat', 657 method_id_var_name='getCompressFormat', 658 java_class_name='', 659 params=[], 660 env_call=('Void', ''), 661 unchecked=False, 662 ), 663 CalledByNative( 664 return_type='List<Bitmap.CompressFormat>', 665 system_class=False, 666 static=False, 667 name='getCompressFormatList', 668 method_id_var_name='getCompressFormatList', 669 java_class_name='', 670 params=[], 671 env_call=('Void', ''), 672 unchecked=False, 673 ), 674 ] 675 self.assertListEquals(golden_called_by_natives, called_by_natives) 676 h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', 677 [], called_by_natives, [], 678 TestOptions()) 679 self.assertGoldenTextEquals(h.GetContent()) 680 681 def testCalledByNativeParseError(self): 682 try: 683 jni_generator.ExtractCalledByNatives(""" 684@CalledByNative 685public static int foo(); // This one is fine 686 687@CalledByNative 688scooby doo 689""") 690 self.fail('Expected a ParseError') 691 except jni_generator.ParseError, e: 692 self.assertEquals(('@CalledByNative', 'scooby doo'), e.context_lines) 693 694 def testFullyQualifiedClassName(self): 695 contents = """ 696// Copyright (c) 2010 The Chromium Authors. All rights reserved. 697// Use of this source code is governed by a BSD-style license that can be 698// found in the LICENSE file. 699 700package org.chromium.content.browser; 701 702import org.chromium.base.BuildInfo; 703""" 704 self.assertEquals('org/chromium/content/browser/Foo', 705 jni_generator.ExtractFullyQualifiedJavaClassName( 706 'org/chromium/content/browser/Foo.java', contents)) 707 self.assertEquals('org/chromium/content/browser/Foo', 708 jni_generator.ExtractFullyQualifiedJavaClassName( 709 'frameworks/Foo.java', contents)) 710 self.assertRaises(SyntaxError, 711 jni_generator.ExtractFullyQualifiedJavaClassName, 712 'com/foo/Bar', 'no PACKAGE line') 713 714 def testMethodNameMangling(self): 715 self.assertEquals('closeV', 716 jni_generator.GetMangledMethodName('close', [], 'void')) 717 self.assertEquals('readI_AB_I_I', 718 jni_generator.GetMangledMethodName('read', 719 [Param(name='p1', 720 datatype='byte[]'), 721 Param(name='p2', 722 datatype='int'), 723 Param(name='p3', 724 datatype='int'),], 725 'int')) 726 self.assertEquals('openJIIS_JLS', 727 jni_generator.GetMangledMethodName('open', 728 [Param(name='p1', 729 datatype='java/lang/String'),], 730 'java/io/InputStream')) 731 732 def testFromJavaPGenerics(self): 733 contents = """ 734public abstract class java.util.HashSet<T> extends java.util.AbstractSet<E> 735 implements java.util.Set<E>, java.lang.Cloneable, java.io.Serializable { 736 public void dummy(); 737 Signature: ()V 738} 739""" 740 jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'), 741 TestOptions()) 742 self.assertEquals(1, len(jni_from_javap.called_by_natives)) 743 self.assertGoldenTextEquals(jni_from_javap.GetContent()) 744 745 def testSnippnetJavap6_7_8(self): 746 content_javap6 = """ 747public class java.util.HashSet { 748public boolean add(java.lang.Object); 749 Signature: (Ljava/lang/Object;)Z 750} 751""" 752 753 content_javap7 = """ 754public class java.util.HashSet { 755public boolean add(E); 756 Signature: (Ljava/lang/Object;)Z 757} 758""" 759 760 content_javap8 = """ 761public class java.util.HashSet { 762 public boolean add(E); 763 descriptor: (Ljava/lang/Object;)Z 764} 765""" 766 767 jni_from_javap6 = jni_generator.JNIFromJavaP(content_javap6.split('\n'), 768 TestOptions()) 769 jni_from_javap7 = jni_generator.JNIFromJavaP(content_javap7.split('\n'), 770 TestOptions()) 771 jni_from_javap8 = jni_generator.JNIFromJavaP(content_javap8.split('\n'), 772 TestOptions()) 773 self.assertTrue(jni_from_javap6.GetContent()) 774 self.assertTrue(jni_from_javap7.GetContent()) 775 self.assertTrue(jni_from_javap8.GetContent()) 776 # Ensure the javap7 is correctly parsed and uses the Signature field rather 777 # than the "E" parameter. 778 self.assertTextEquals(jni_from_javap6.GetContent(), 779 jni_from_javap7.GetContent()) 780 # Ensure the javap8 is correctly parsed and uses the descriptor field. 781 self.assertTextEquals(jni_from_javap7.GetContent(), 782 jni_from_javap8.GetContent()) 783 784 def testFromJavaP(self): 785 contents = self._ReadGoldenFile(os.path.join(os.path.dirname(sys.argv[0]), 786 'testInputStream.javap')) 787 jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'), 788 TestOptions()) 789 self.assertEquals(10, len(jni_from_javap.called_by_natives)) 790 self.assertGoldenTextEquals(jni_from_javap.GetContent()) 791 792 def testConstantsFromJavaP(self): 793 for f in ['testMotionEvent.javap', 'testMotionEvent.javap7']: 794 contents = self._ReadGoldenFile(os.path.join(os.path.dirname(sys.argv[0]), 795 f)) 796 jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'), 797 TestOptions()) 798 self.assertEquals(86, len(jni_from_javap.called_by_natives)) 799 self.assertGoldenTextEquals(jni_from_javap.GetContent()) 800 801 def testREForNatives(self): 802 # We should not match "native SyncSetupFlow" inside the comment. 803 test_data = """ 804 /** 805 * Invoked when the setup process is complete so we can disconnect from the 806 * native-side SyncSetupFlowHandler. 807 */ 808 public void destroy() { 809 Log.v(TAG, "Destroying native SyncSetupFlow"); 810 if (mNativeSyncSetupFlow != 0) { 811 nativeSyncSetupEnded(mNativeSyncSetupFlow); 812 mNativeSyncSetupFlow = 0; 813 } 814 } 815 private native void nativeSyncSetupEnded( 816 int nativeAndroidSyncSetupFlowHandler); 817 """ 818 jni_from_java = jni_generator.JNIFromJavaSource( 819 test_data, 'foo/bar', TestOptions()) 820 821 def testRaisesOnNonJNIMethod(self): 822 test_data = """ 823 class MyInnerClass { 824 private int Foo(int p0) { 825 } 826 } 827 """ 828 self.assertRaises(SyntaxError, 829 jni_generator.JNIFromJavaSource, 830 test_data, 'foo/bar', TestOptions()) 831 832 def testJniSelfDocumentingExample(self): 833 script_dir = os.path.dirname(sys.argv[0]) 834 content = file(os.path.join(script_dir, 835 'java/src/org/chromium/example/jni_generator/SampleForTests.java') 836 ).read() 837 golden_file = os.path.join(script_dir, 'SampleForTests_jni.golden') 838 golden_content = file(golden_file).read() 839 jni_from_java = jni_generator.JNIFromJavaSource( 840 content, 'org/chromium/example/jni_generator/SampleForTests', 841 TestOptions()) 842 generated_text = jni_from_java.GetContent() 843 if not self.compareText(golden_content, generated_text): 844 if os.environ.get(REBASELINE_ENV): 845 with file(golden_file, 'w') as f: 846 f.write(generated_text) 847 return 848 self.fail('testJniSelfDocumentingExample') 849 850 def testNoWrappingPreprocessorLines(self): 851 test_data = """ 852 package com.google.lookhowextremelylongiam.snarf.icankeepthisupallday; 853 854 class ReallyLongClassNamesAreAllTheRage { 855 private static native int nativeTest(); 856 } 857 """ 858 jni_from_java = jni_generator.JNIFromJavaSource( 859 test_data, ('com/google/lookhowextremelylongiam/snarf/' 860 'icankeepthisupallday/ReallyLongClassNamesAreAllTheRage'), 861 TestOptions()) 862 jni_lines = jni_from_java.GetContent().split('\n') 863 line = filter(lambda line: line.lstrip().startswith('#ifndef'), 864 jni_lines)[0] 865 self.assertTrue(len(line) > 80, 866 ('Expected #ifndef line to be > 80 chars: ', line)) 867 868 def testImports(self): 869 import_header = """ 870// Copyright (c) 2012 The Chromium Authors. All rights reserved. 871// Use of this source code is governed by a BSD-style license that can be 872// found in the LICENSE file. 873 874package org.chromium.content.app; 875 876import android.app.Service; 877import android.content.Context; 878import android.content.Intent; 879import android.graphics.SurfaceTexture; 880import android.os.Bundle; 881import android.os.IBinder; 882import android.os.ParcelFileDescriptor; 883import android.os.Process; 884import android.os.RemoteException; 885import android.util.Log; 886import android.view.Surface; 887 888import java.util.ArrayList; 889 890import org.chromium.base.annotations.CalledByNative; 891import org.chromium.base.annotations.JNINamespace; 892import org.chromium.content.app.ContentMain; 893import org.chromium.content.browser.SandboxedProcessConnection; 894import org.chromium.content.common.ISandboxedProcessCallback; 895import org.chromium.content.common.ISandboxedProcessService; 896import org.chromium.content.common.WillNotRaise.AnException; 897import org.chromium.content.common.WillRaise.AnException; 898 899import static org.chromium.Bar.Zoo; 900 901class Foo { 902 public static class BookmarkNode implements Parcelable { 903 } 904 public interface PasswordListObserver { 905 } 906} 907 """ 908 jni_generator.JniParams.SetFullyQualifiedClass( 909 'org/chromium/content/app/Foo') 910 jni_generator.JniParams.ExtractImportsAndInnerClasses(import_header) 911 self.assertTrue('Lorg/chromium/content/common/ISandboxedProcessService' in 912 jni_generator.JniParams._imports) 913 self.assertTrue('Lorg/chromium/Bar/Zoo' in 914 jni_generator.JniParams._imports) 915 self.assertTrue('Lorg/chromium/content/app/Foo$BookmarkNode' in 916 jni_generator.JniParams._inner_classes) 917 self.assertTrue('Lorg/chromium/content/app/Foo$PasswordListObserver' in 918 jni_generator.JniParams._inner_classes) 919 self.assertEquals('Lorg/chromium/content/app/ContentMain$Inner;', 920 jni_generator.JniParams.JavaToJni('ContentMain.Inner')) 921 self.assertRaises(SyntaxError, 922 jni_generator.JniParams.JavaToJni, 923 'AnException') 924 925 def testJniParamsJavaToJni(self): 926 self.assertTextEquals('I', JniParams.JavaToJni('int')) 927 self.assertTextEquals('[B', JniParams.JavaToJni('byte[]')) 928 self.assertTextEquals( 929 '[Ljava/nio/ByteBuffer;', JniParams.JavaToJni('java/nio/ByteBuffer[]')) 930 931 def testNativesLong(self): 932 test_options = TestOptions() 933 test_options.ptr_type = 'long' 934 test_data = """" 935 private native void nativeDestroy(long nativeChromeBrowserProvider); 936 """ 937 jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data) 938 natives = jni_generator.ExtractNatives(test_data, test_options.ptr_type) 939 golden_natives = [ 940 NativeMethod(return_type='void', static=False, name='Destroy', 941 params=[Param(datatype='long', 942 name='nativeChromeBrowserProvider')], 943 java_class_name=None, 944 type='method', 945 p0_type='ChromeBrowserProvider', 946 ptr_type=test_options.ptr_type), 947 ] 948 self.assertListEquals(golden_natives, natives) 949 h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', 950 natives, [], [], test_options) 951 self.assertGoldenTextEquals(h.GetContent()) 952 953 def testMainDexFile(self): 954 test_data = """ 955 package org.chromium.example.jni_generator; 956 957 @MainDex 958 class Test { 959 private static native int nativeStaticMethod(long nativeTest, int arg1); 960 } 961 """ 962 options = TestOptions() 963 jni_from_java = jni_generator.JNIFromJavaSource( 964 test_data, 'org/chromium/foo/Bar', options) 965 self.assertGoldenTextEquals(jni_from_java.GetContent()) 966 967 def testNonMainDexFile(self): 968 test_data = """ 969 package org.chromium.example.jni_generator; 970 971 class Test { 972 private static native int nativeStaticMethod(long nativeTest, int arg1); 973 } 974 """ 975 options = TestOptions() 976 jni_from_java = jni_generator.JNIFromJavaSource( 977 test_data, 'org/chromium/foo/Bar', options) 978 self.assertGoldenTextEquals(jni_from_java.GetContent()) 979 980 def testNativeExportsOnlyOption(self): 981 test_data = """ 982 package org.chromium.example.jni_generator; 983 984 /** The pointer to the native Test. */ 985 long nativeTest; 986 987 class Test { 988 private static native int nativeStaticMethod(long nativeTest, int arg1); 989 private native int nativeMethod(long nativeTest, int arg1); 990 @CalledByNative 991 private void testMethodWithParam(int iParam); 992 @CalledByNative 993 private String testMethodWithParamAndReturn(int iParam); 994 @CalledByNative 995 private static int testStaticMethodWithParam(int iParam); 996 @CalledByNative 997 private static double testMethodWithNoParam(); 998 @CalledByNative 999 private static String testStaticMethodWithNoParam(); 1000 1001 class MyInnerClass { 1002 @NativeCall("MyInnerClass") 1003 private native int nativeInit(); 1004 } 1005 class MyOtherInnerClass { 1006 @NativeCall("MyOtherInnerClass") 1007 private native int nativeInit(); 1008 } 1009 } 1010 """ 1011 options = TestOptions() 1012 options.native_exports_optional = False 1013 jni_from_java = jni_generator.JNIFromJavaSource( 1014 test_data, 'org/chromium/example/jni_generator/SampleForTests', options) 1015 self.assertGoldenTextEquals(jni_from_java.GetContent()) 1016 1017 def testOuterInnerRaises(self): 1018 test_data = """ 1019 package org.chromium.media; 1020 1021 @CalledByNative 1022 static int getCaptureFormatWidth(VideoCapture.CaptureFormat format) { 1023 return format.getWidth(); 1024 } 1025 """ 1026 def willRaise(): 1027 jni_generator.JNIFromJavaSource( 1028 test_data, 1029 'org/chromium/media/VideoCaptureFactory', 1030 TestOptions()) 1031 self.assertRaises(SyntaxError, willRaise) 1032 1033 def testSingleJNIAdditionalImport(self): 1034 test_data = """ 1035 package org.chromium.foo; 1036 1037 @JNIAdditionalImport(Bar.class) 1038 class Foo { 1039 1040 @CalledByNative 1041 private static void calledByNative(Bar.Callback callback) { 1042 } 1043 1044 private static native void nativeDoSomething(Bar.Callback callback); 1045 } 1046 """ 1047 jni_from_java = jni_generator.JNIFromJavaSource(test_data, 1048 'org/chromium/foo/Foo', 1049 TestOptions()) 1050 self.assertGoldenTextEquals(jni_from_java.GetContent()) 1051 1052 def testMultipleJNIAdditionalImport(self): 1053 test_data = """ 1054 package org.chromium.foo; 1055 1056 @JNIAdditionalImport({Bar1.class, Bar2.class}) 1057 class Foo { 1058 1059 @CalledByNative 1060 private static void calledByNative(Bar1.Callback callback1, 1061 Bar2.Callback callback2) { 1062 } 1063 1064 private static native void nativeDoSomething(Bar1.Callback callback1, 1065 Bar2.Callback callback2); 1066 } 1067 """ 1068 jni_from_java = jni_generator.JNIFromJavaSource(test_data, 1069 'org/chromium/foo/Foo', 1070 TestOptions()) 1071 self.assertGoldenTextEquals(jni_from_java.GetContent()) 1072 1073 1074def TouchStamp(stamp_path): 1075 dir_name = os.path.dirname(stamp_path) 1076 if not os.path.isdir(dir_name): 1077 os.makedirs(dir_name) 1078 1079 with open(stamp_path, 'a'): 1080 os.utime(stamp_path, None) 1081 1082 1083def main(argv): 1084 parser = optparse.OptionParser() 1085 parser.add_option('--stamp', help='Path to touch on success.') 1086 options, _ = parser.parse_args(argv[1:]) 1087 1088 test_result = unittest.main(argv=argv[0:1], exit=False) 1089 1090 if test_result.result.wasSuccessful() and options.stamp: 1091 TouchStamp(options.stamp) 1092 1093 return not test_result.result.wasSuccessful() 1094 1095 1096if __name__ == '__main__': 1097 sys.exit(main(sys.argv)) 1098