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