Home | History | Annotate | Download | only in jni_generator
      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 os
     17 import sys
     18 import unittest
     19 import jni_generator
     20 from jni_generator import CalledByNative, JniParams, NativeMethod, Param
     21 
     22 
     23 SCRIPT_NAME = 'base/android/jni_generator/jni_generator.py'
     24 INCLUDES = (
     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.
     30 REBASELINE_ENV = 'REBASELINE'
     31 
     32 class 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 
     47 class 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
    665 public static int foo(); // This one is fine
    666 
    667 @CalledByNative
    668 scooby 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 
    680 package org.chromium.content.browser;
    681 
    682 import 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 = """
    714 public 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 = """
    727 public class java.util.HashSet {
    728 public boolean add(java.lang.Object);
    729  Signature: (Ljava/lang/Object;)Z
    730 }
    731 """
    732 
    733     content_javap7 = """
    734 public class java.util.HashSet {
    735 public 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 
    867 package org.chromium.content.app;
    868 
    869 import android.app.Service;
    870 import android.content.Context;
    871 import android.content.Intent;
    872 import android.graphics.SurfaceTexture;
    873 import android.os.Bundle;
    874 import android.os.IBinder;
    875 import android.os.ParcelFileDescriptor;
    876 import android.os.Process;
    877 import android.os.RemoteException;
    878 import android.util.Log;
    879 import android.view.Surface;
    880 
    881 import java.util.ArrayList;
    882 
    883 import org.chromium.base.CalledByNative;
    884 import org.chromium.base.JNINamespace;
    885 import org.chromium.content.app.ContentMain;
    886 import org.chromium.content.browser.SandboxedProcessConnection;
    887 import org.chromium.content.common.ISandboxedProcessCallback;
    888 import org.chromium.content.common.ISandboxedProcessService;
    889 import org.chromium.content.common.WillNotRaise.AnException;
    890 import org.chromium.content.common.WillRaise.AnException;
    891 
    892 import static org.chromium.Bar.Zoo;
    893 
    894 class 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 
   1127 if __name__ == '__main__':
   1128   unittest.main()
   1129