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