xref: /aosp_15_r20/external/fbjni/test/FBJniTests.java (revision 65c59e023c5336bbd4a23be7af78407e3d80e7e7)
1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.facebook.jni;
18 
19 import static org.assertj.core.api.Assertions.assertThat;
20 import static org.mockito.Mockito.verify;
21 
22 import com.facebook.jni.annotations.DoNotStrip;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.concurrent.Callable;
26 import javax.annotation.Nullable;
27 import org.assertj.core.api.Fail;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.mockito.Mock;
31 import org.mockito.runners.MockitoJUnitRunner;
32 
33 @RunWith(MockitoJUnitRunner.class)
34 public class FBJniTests extends BaseFBJniTests {
35   class CustomException extends Throwable {
36     int mGetMessageCalls = 0;
37 
38     @Override
getMessage()39     public String getMessage() {
40       return "getMessages: " + (++mGetMessageCalls);
41     }
42   }
43 
44   public interface Callbacks {
voidFoo()45     void voidFoo();
46 
booleanFoo()47     boolean booleanFoo();
48 
byteFoo()49     byte byteFoo();
50 
charFoo()51     char charFoo();
52 
shortFoo()53     short shortFoo();
54 
intFoo()55     int intFoo();
56 
longFoo()57     long longFoo();
58 
floatFoo()59     float floatFoo();
60 
doubleFoo()61     double doubleFoo();
62 
objectFoo()63     Object objectFoo();
64 
stringFoo()65     String stringFoo();
66   }
67 
68   public static class TestThing {
69     int foo;
70   }
71 
72   @Mock private static Callbacks mCallbacksMock;
73 
74   private int mIntFieldTest;
75   private String mStringFieldTest;
76   private TestThing mReferenceFieldTest;
77   private static int sIntFieldTest;
78   private static String sStringFieldTest;
79   private static TestThing sReferenceFieldTest;
80 
81   @DoNotStrip // Resolved from fbjni_tests::TestFieldAccess
bar(double d)82   int bar(double d) {
83     return 42;
84   }
85 
86   // Test case for nonvirtual function
nonVirtualMethod(boolean s)87   public boolean nonVirtualMethod(boolean s) {
88     return s;
89   }
90 
verifyAllCallbacksCalled(Callbacks mock)91   private static void verifyAllCallbacksCalled(Callbacks mock) {
92     verify(mock).voidFoo();
93     verify(mock).booleanFoo();
94     verify(mock).byteFoo();
95     verify(mock).charFoo();
96     verify(mock).shortFoo();
97     verify(mock).intFoo();
98     verify(mock).longFoo();
99     verify(mock).floatFoo();
100     verify(mock).doubleFoo();
101     verify(mock).objectFoo();
102     verify(mock).stringFoo();
103   }
104 
105   // Instead of mocking, lets call non-static functions and verify them.
voidFooStatic()106   public static void voidFooStatic() {
107     mCallbacksMock.voidFoo();
108   }
109 
booleanFooStatic()110   public static boolean booleanFooStatic() {
111     return mCallbacksMock.booleanFoo();
112   }
113 
byteFooStatic()114   public static byte byteFooStatic() {
115     return mCallbacksMock.byteFoo();
116   }
117 
charFooStatic(char c, int s)118   public static char charFooStatic(char c, int s) {
119     return mCallbacksMock.charFoo();
120   }
121 
shortFooStatic(short s, short t)122   public static short shortFooStatic(short s, short t) {
123     return mCallbacksMock.shortFoo();
124   }
125 
intFooStatic(int s)126   public static int intFooStatic(int s) {
127     return mCallbacksMock.intFoo();
128   }
129 
longFooStatic()130   public static long longFooStatic() {
131     return mCallbacksMock.longFoo();
132   }
133 
floatFooStatic()134   public static float floatFooStatic() {
135     return mCallbacksMock.floatFoo();
136   }
137 
doubleFooStatic()138   public static double doubleFooStatic() {
139     return mCallbacksMock.doubleFoo();
140   }
141 
objectFooStatic()142   public static Object objectFooStatic() {
143     return mCallbacksMock.objectFoo();
144   }
145 
stringFooStatic()146   public static String stringFooStatic() {
147     return mCallbacksMock.stringFoo();
148   }
149 
150   @Test
resolveClass()151   public void resolveClass() throws ClassNotFoundException {
152     assertThat(nativeTestClassResolution("java/lang/Object")).isTrue();
153   }
154 
155   // Some versions of Android throw ClassNotFoundException while others throw NoClassDefFoundError.
156   // Flatten that to always be ClassNotFoundException.
wrapClassLoadingErrors(Callable<?> code)157   private static void wrapClassLoadingErrors(Callable<?> code) throws Exception {
158     try {
159       code.call();
160     } catch (NoClassDefFoundError ex) {
161       throw new ClassNotFoundException("chained NoClassDefFoundError", ex);
162     }
163   }
164 
165   @Test(expected = ClassNotFoundException.class)
failingToResolveClass()166   public void failingToResolveClass() throws Exception {
167     wrapClassLoadingErrors(
168         new Callable<Boolean>() {
169           @Override
170           public Boolean call() throws Exception {
171             return nativeTestClassResolution("ThisClassDoesNotExist");
172           }
173         });
174   }
175 
nativeTestClassResolution(String className)176   private native boolean nativeTestClassResolution(String className) throws ClassNotFoundException;
177 
178   @Test
lazyClassResolution()179   public void lazyClassResolution() throws ClassNotFoundException {
180     assertThat(nativeTestLazyClassResolution("java/lang/Object")).isTrue();
181   }
182 
183   @Test(expected = ClassNotFoundException.class)
failedLazyClassResolution()184   public void failedLazyClassResolution() throws Exception {
185     wrapClassLoadingErrors(
186         new Callable<Boolean>() {
187           @Override
188           public Boolean call() throws Exception {
189             return nativeTestLazyClassResolution("ThisClassDoesNotExist");
190           }
191         });
192   }
193 
nativeTestLazyClassResolution(String className)194   private native boolean nativeTestLazyClassResolution(String className)
195       throws ClassNotFoundException;
196 
197   @Test
instanceCreation()198   public void instanceCreation() {
199     assertThat(nativeCreateInstanceOf("java/lang/String"))
200         .isInstanceOf(String.class)
201         .isEqualTo("java/lang/String");
202   }
203 
nativeCreateInstanceOf(String className)204   private native Object nativeCreateInstanceOf(String className);
205 
206   @Test
typeDescriptors()207   public void typeDescriptors() {
208     assertThat(nativeTestTypeDescriptors()).isTrue();
209   }
210 
nativeTestTypeDescriptors()211   private native boolean nativeTestTypeDescriptors();
212 
213   @Test
resolveVirtualMethod()214   public void resolveVirtualMethod() throws ClassNotFoundException, NoSuchMethodException {
215     assertThat(nativeTestVirtualMethodResolution_I("java/lang/Object", "hashCode")).isTrue();
216   }
217 
218   @Test
resolveVirtualMethodWithArray()219   public void resolveVirtualMethodWithArray() throws ClassNotFoundException, NoSuchMethodException {
220     assertThat(nativeTestVirtualMethodResolution_arrB("java/lang/String", "getBytes")).isTrue();
221   }
222 
223   @Test
resolveVirtualMethodWithObjectArray()224   public void resolveVirtualMethodWithObjectArray()
225       throws ClassNotFoundException, NoSuchMethodException {
226     assertThat(nativeTestVirtualMethodResolution_S_arrS("java/lang/String", "split")).isTrue();
227   }
228 
229   @Test
resolveVirtualMethodWithObjectArrayArray()230   public void resolveVirtualMethodWithObjectArrayArray()
231       throws ClassNotFoundException, NoSuchMethodException {
232     assertThat(
233             nativeTestVirtualMethodResolution_arrarrS(
234                 "com/facebook/jni/FBJniTests", "returnMultidimensionalObjectArray"))
235         .isTrue();
236   }
237 
returnMultidimensionalObjectArray()238   public static String[][] returnMultidimensionalObjectArray() {
239     return null;
240   }
241 
242   @Test
resolveVirtualMethodWithPrimitiveArrayArray()243   public void resolveVirtualMethodWithPrimitiveArrayArray()
244       throws ClassNotFoundException, NoSuchMethodException {
245     assertThat(
246             nativeTestVirtualMethodResolution_arrarrI(
247                 "com/facebook/jni/FBJniTests", "returnMultidimensionalPrimitiveArray"))
248         .isTrue();
249   }
250 
returnMultidimensionalPrimitiveArray()251   public static int[][] returnMultidimensionalPrimitiveArray() {
252     return null;
253   }
254 
255   @Test(expected = NoSuchMethodError.class)
failingToResolveVirtualMethod()256   public void failingToResolveVirtualMethod() throws ClassNotFoundException, NoSuchMethodError {
257     nativeTestVirtualMethodResolution_I("java/lang/Object", "ThisMethodDoesNotExist");
258   }
259 
nativeTestVirtualMethodResolution_I(String className, String methodName)260   private native boolean nativeTestVirtualMethodResolution_I(String className, String methodName)
261       throws ClassNotFoundException, NoSuchMethodError;
262 
nativeTestVirtualMethodResolution_arrB(String className, String methodName)263   private native boolean nativeTestVirtualMethodResolution_arrB(String className, String methodName)
264       throws ClassNotFoundException, NoSuchMethodError;
265 
nativeTestVirtualMethodResolution_S_arrS( String className, String methodName)266   private native boolean nativeTestVirtualMethodResolution_S_arrS(
267       String className, String methodName) throws ClassNotFoundException, NoSuchMethodError;
268 
nativeTestVirtualMethodResolution_arrarrS( String className, String methodName)269   private native boolean nativeTestVirtualMethodResolution_arrarrS(
270       String className, String methodName) throws ClassNotFoundException, NoSuchMethodError;
271 
nativeTestVirtualMethodResolution_arrarrI( String className, String methodName)272   private native boolean nativeTestVirtualMethodResolution_arrarrI(
273       String className, String methodName) throws ClassNotFoundException, NoSuchMethodError;
274 
275   @Test
lazyMethodResolution()276   public void lazyMethodResolution() throws ClassNotFoundException, NoSuchMethodError {
277     assertThat(nativeTestLazyVirtualMethodResolution_I("java/lang/Object", "hashCode")).isTrue();
278   }
279 
280   @Test(expected = NoSuchMethodError.class)
failedLazyMethodResolution()281   public void failedLazyMethodResolution() throws ClassNotFoundException, NoSuchMethodError {
282     nativeTestLazyVirtualMethodResolution_I("java/lang/Object", "ThisMethodDoesNotExist");
283   }
284 
nativeTestLazyVirtualMethodResolution_I( String className, String methodName)285   private native boolean nativeTestLazyVirtualMethodResolution_I(
286       String className, String methodName);
287 
288   @Test
callbacksUsingJMethod()289   public void callbacksUsingJMethod() {
290     nativeTestJMethodCallbacks(mCallbacksMock);
291     verifyAllCallbacksCalled(mCallbacksMock);
292   }
293 
nativeTestJMethodCallbacks(Callbacks callbacks)294   private native void nativeTestJMethodCallbacks(Callbacks callbacks);
295 
296   @Test
callbacksUsingJStaticMethod()297   public void callbacksUsingJStaticMethod() {
298     nativeTestJStaticMethodCallbacks();
299     verifyAllCallbacksCalled(mCallbacksMock);
300   }
301 
nativeTestJStaticMethodCallbacks()302   private native void nativeTestJStaticMethodCallbacks();
303 
304   @Test
isAssignableFrom()305   public void isAssignableFrom() {
306     assertThat(nativeTestIsAssignableFrom(String.class, String.class)).isTrue();
307     assertThat(nativeTestIsAssignableFrom(String.class, Object.class)).isFalse();
308     assertThat(nativeTestIsAssignableFrom(Object.class, String.class)).isTrue();
309     assertThat(nativeTestIsAssignableFrom(ArrayList.class, Iterable.class)).isFalse();
310     assertThat(nativeTestIsAssignableFrom(Iterable.class, ArrayList.class)).isTrue();
311   }
312 
nativeTestIsAssignableFrom(Class cls1, Class cls2)313   private native boolean nativeTestIsAssignableFrom(Class cls1, Class cls2);
314 
315   @Test
isInstanceOf()316   public void isInstanceOf() {
317     assertThat(nativeTestIsInstanceOf("", String.class)).isTrue();
318     assertThat(nativeTestIsInstanceOf("", Object.class)).isTrue();
319     assertThat(nativeTestIsInstanceOf(new Object(), String.class)).isFalse();
320     assertThat(nativeTestIsInstanceOf(new ArrayList(), Iterable.class)).isTrue();
321     assertThat(nativeTestIsInstanceOf(null, Iterable.class)).isTrue();
322   }
323 
nativeTestIsInstanceOf(Object object, Class cls)324   private native boolean nativeTestIsInstanceOf(Object object, Class cls);
325 
326   @Test
isSameObject()327   public void isSameObject() {
328     Object anObject = new Object();
329     Object anotherObject = new Object();
330     assertThat(nativeTestIsSameObject(anObject, anObject)).isTrue();
331     assertThat(nativeTestIsSameObject(anObject, anotherObject)).isFalse();
332     assertThat(nativeTestIsSameObject(null, anObject)).isFalse();
333     assertThat(nativeTestIsSameObject(anObject, null)).isFalse();
334     assertThat(nativeTestIsSameObject(null, null)).isTrue();
335   }
336 
nativeTestIsSameObject(Object a, Object b)337   private native boolean nativeTestIsSameObject(Object a, Object b);
338 
339   @Test
testGetSuperClass()340   public void testGetSuperClass() {
341     Class testClass = String.class;
342     Class superClass = Object.class;
343     Class notSuperClass = Integer.class;
344 
345     assertThat(nativeTestGetSuperclass(testClass, superClass)).isTrue();
346     assertThat(nativeTestGetSuperclass(testClass, notSuperClass)).isFalse();
347   }
348 
nativeTestGetSuperclass(Class testClass, Class superOfTest)349   private native boolean nativeTestGetSuperclass(Class testClass, Class superOfTest);
350 
351   @Test
testWeakRefs()352   public void testWeakRefs() {
353     assertThat(nativeTestWeakRefs()).isTrue();
354   }
355 
nativeTestWeakRefs()356   private native boolean nativeTestWeakRefs();
357 
358   @Test
testAliasRefs()359   public void testAliasRefs() {
360     assertThat(nativeTestAlias()).isTrue();
361   }
362 
nativeTestAlias()363   private native boolean nativeTestAlias();
364 
365   @Test
testAliasRefConversions()366   public void testAliasRefConversions() {
367     assertThat(nativeTestAliasRefConversions()).isTrue();
368   }
369 
nativeTestAliasRefConversions()370   private native boolean nativeTestAliasRefConversions();
371 
372   @Test
testNullJString()373   public void testNullJString() {
374     assertThat(nativeTestNullJString()).isTrue();
375   }
376 
nativeTestNullJString()377   private native boolean nativeTestNullJString();
378 
379   @Test
testSwap()380   public void testSwap() {
381     assertThat(nativeTestSwap(new Object())).isTrue();
382   }
383 
nativeTestSwap(Object other)384   private native boolean nativeTestSwap(Object other);
385 
386   @Test
testEqualOperator()387   public void testEqualOperator() {
388     assertThat(nativeTestEqualOperator(new Object())).isTrue();
389   }
390 
nativeTestEqualOperator(Object other)391   private native boolean nativeTestEqualOperator(Object other);
392 
393   @Test
testRelaseAlias()394   public void testRelaseAlias() {
395     assertThat(nativeTestReleaseAlias()).isTrue();
396   }
397 
nativeTestReleaseAlias()398   private native boolean nativeTestReleaseAlias();
399 
400   @Test
testLockingWeakReferences()401   public void testLockingWeakReferences() {
402     assertThat(nativeTestLockingWeakReferences()).isTrue();
403   }
404 
nativeTestLockingWeakReferences()405   private native boolean nativeTestLockingWeakReferences();
406 
407   @Test
testCreatingReferences()408   public void testCreatingReferences() {
409     assertThat(nativeTestCreatingReferences()).isTrue();
410   }
411 
nativeTestCreatingReferences()412   private native boolean nativeTestCreatingReferences();
413 
414   @Test
testAssignmentAndCopyConstructors()415   public void testAssignmentAndCopyConstructors() {
416     assertThat(nativeTestAssignmentAndCopyConstructors()).isTrue();
417   }
418 
nativeTestAssignmentAndCopyConstructors()419   private native boolean nativeTestAssignmentAndCopyConstructors();
420 
421   @Test
testAssignmentAndCopyCrossTypes()422   public void testAssignmentAndCopyCrossTypes() {
423     assertThat(nativeTestAssignmentAndCopyCrossTypes()).isTrue();
424   }
425 
nativeTestAssignmentAndCopyCrossTypes()426   private native boolean nativeTestAssignmentAndCopyCrossTypes();
427 
428   @Test
testNullReferences()429   public void testNullReferences() {
430     assertThat(nativeTestNullReferences()).isTrue();
431   }
432 
nativeTestNullReferences()433   private native boolean nativeTestNullReferences();
434 
435   @Test
testAutoAliasRefReturningVoid()436   public void testAutoAliasRefReturningVoid() {
437     nativeTestAutoAliasRefReturningVoid();
438   }
439 
nativeTestAutoAliasRefReturningVoid()440   private native void nativeTestAutoAliasRefReturningVoid();
441 
442   @Test
testFieldAccess()443   public void testFieldAccess() {
444     mIntFieldTest = 17;
445     assertThat(nativeTestFieldAccess("mIntFieldTest", mIntFieldTest, 42)).isTrue();
446     assertThat(mIntFieldTest).isEqualTo(42);
447   }
448 
nativeTestFieldAccess(String name, int oldVal, int newVal)449   private native boolean nativeTestFieldAccess(String name, int oldVal, int newVal);
450 
451   @Test
testStringFieldAccess()452   public void testStringFieldAccess() {
453     mStringFieldTest = "initial";
454     assertThat(nativeTestStringFieldAccess("mStringFieldTest", mStringFieldTest, "final")).isTrue();
455     assertThat(mStringFieldTest).isEqualTo("final");
456   }
457 
nativeTestStringFieldAccess(String name, String oldVal, String newVal)458   private native boolean nativeTestStringFieldAccess(String name, String oldVal, String newVal);
459 
460   @Test
testReferenceFieldAccess()461   public void testReferenceFieldAccess() {
462     for (boolean useWrapper : new boolean[] {false, true}) {
463       mReferenceFieldTest = new TestThing();
464       TestThing newthing = new TestThing();
465 
466       assertThat(
467               nativeTestReferenceFieldAccess(
468                   "mReferenceFieldTest", mReferenceFieldTest, newthing, useWrapper))
469           .isTrue();
470       assertThat(mReferenceFieldTest).isEqualTo(newthing);
471     }
472   }
473 
nativeTestReferenceFieldAccess( String name, Object oldVal, Object newVal, boolean useWrapper)474   private native boolean nativeTestReferenceFieldAccess(
475       String name, Object oldVal, Object newVal, boolean useWrapper);
476 
477   @Test
testStaticFieldAccess()478   public void testStaticFieldAccess() {
479     sIntFieldTest = 17;
480     assertThat(nativeTestStaticFieldAccess("sIntFieldTest", sIntFieldTest, 42)).isTrue();
481     assertThat(sIntFieldTest).isEqualTo(42);
482   }
483 
nativeTestStaticFieldAccess(String name, int oldVal, int newVal)484   private native boolean nativeTestStaticFieldAccess(String name, int oldVal, int newVal);
485 
486   @Test
testStaticStringFieldAccess()487   public void testStaticStringFieldAccess() {
488     sStringFieldTest = "initial";
489     assertThat(nativeTestStaticStringFieldAccess("sStringFieldTest", sStringFieldTest, "final"))
490         .isTrue();
491     assertThat(sStringFieldTest).isEqualTo("final");
492   }
493 
nativeTestStaticStringFieldAccess(String name, String oVal, String nVal)494   private native boolean nativeTestStaticStringFieldAccess(String name, String oVal, String nVal);
495 
496   @Test
testStaticReferenceFieldAccess()497   public void testStaticReferenceFieldAccess() {
498     for (boolean useWrapper : new boolean[] {false, true}) {
499       sReferenceFieldTest = new TestThing();
500       TestThing newthing = new TestThing();
501 
502       assertThat(
503               nativeTestStaticReferenceFieldAccess(
504                   "sReferenceFieldTest", sReferenceFieldTest, newthing, useWrapper))
505           .isTrue();
506       assertThat(sReferenceFieldTest).isEqualTo(newthing);
507     }
508   }
509 
nativeTestStaticReferenceFieldAccess( String name, Object oldVal, Object newVal, boolean useWrapper)510   private native boolean nativeTestStaticReferenceFieldAccess(
511       String name, Object oldVal, Object newVal, boolean useWrapper);
512 
513   @Test
testNonVirtualMethod()514   public void testNonVirtualMethod() {
515     assertThat(nativeTestNonVirtualMethod(true)).isTrue();
516   }
517 
nativeTestNonVirtualMethod(boolean s)518   private native boolean nativeTestNonVirtualMethod(boolean s);
519 
520   @Test
testArrayCreation()521   public void testArrayCreation() {
522     String[] expectedStrings = {"one", "two", "three"};
523     String[] joinedStrings =
524         nativeTestArrayCreation(expectedStrings[0], expectedStrings[1], expectedStrings[2]);
525     assertThat(joinedStrings).isEqualTo(expectedStrings);
526   }
527 
nativeTestArrayCreation(String s0, String s1, String s2)528   private native String[] nativeTestArrayCreation(String s0, String s1, String s2);
529 
530   @Test
testMultidimensionalObjectArray()531   public void testMultidimensionalObjectArray() {
532     String[] strings = {"one", "two", "three"};
533     String[][] expectedStrings = {{"one", "two"}, {"three"}};
534     String[][] joinedStrings =
535         nativeTestMultidimensionalObjectArray(strings[0], strings[1], strings[2]);
536     assertThat(joinedStrings).isEqualTo(expectedStrings);
537   }
538 
nativeTestMultidimensionalObjectArray(String s0, String s1, String s2)539   private native String[][] nativeTestMultidimensionalObjectArray(String s0, String s1, String s2);
540 
541   @Test
testMultidimensionalPrimitiveArray()542   public void testMultidimensionalPrimitiveArray() {
543     int[] nums = {1, 2, 3};
544     int[][] expectedNums = {{1, 2}, {3}};
545     int[][] gotNums = nativeTestMultidimensionalPrimitiveArray(nums[0], nums[1], nums[2]);
546     assertThat(gotNums).isEqualTo(expectedNums);
547   }
548 
nativeTestMultidimensionalPrimitiveArray(int i0, int i1, int i2)549   private native int[][] nativeTestMultidimensionalPrimitiveArray(int i0, int i1, int i2);
550 
551   @Nullable private String[] mCapturedStringArray = null;
552 
553   @DoNotStrip
captureStringArray(String[] input)554   String captureStringArray(String[] input) {
555     mCapturedStringArray = input;
556     return "Stub";
557   }
558 
559   @Test
testBuildStringArray()560   public void testBuildStringArray() throws Exception {
561     String[] input = {"Four", "score", "and", "seven", "beers", "ago"};
562     nativeTestBuildStringArray(input);
563     assertThat(mCapturedStringArray).isEqualTo(input);
564   }
565 
nativeTestBuildStringArray(String... input)566   private native String nativeTestBuildStringArray(String... input);
567 
methodResolutionWithCxxTypes(String t, long val)568   public Object methodResolutionWithCxxTypes(String t, long val) {
569     if (!"test".equals(t) || val != 3) throw new RuntimeException();
570     return null;
571   }
572 
methodResolutionWithCxxTypesVoid(String t, long val)573   public void methodResolutionWithCxxTypesVoid(String t, long val) {
574     if (!"test".equals(t) || val != 3) throw new RuntimeException();
575   }
576 
methodResolutionWithCxxTypesInt(String t, long val)577   public int methodResolutionWithCxxTypesInt(String t, long val) {
578     if (!"test".equals(t) || val != 3) throw new RuntimeException();
579     return 0;
580   }
581 
methodResolutionWithCxxTypesStatic(String t, long val)582   public static Object methodResolutionWithCxxTypesStatic(String t, long val) {
583     if (!"test".equals(t) || val != 3) throw new RuntimeException();
584     return null;
585   }
586 
methodResolutionWithCxxTypesVoidStatic(String t, long val)587   public static void methodResolutionWithCxxTypesVoidStatic(String t, long val) {
588     if (!"test".equals(t) || val != 3) throw new RuntimeException();
589   }
590 
methodResolutionWithCxxTypesIntStatic(String t, long val)591   public static int methodResolutionWithCxxTypesIntStatic(String t, long val) {
592     if (!"test".equals(t) || val != 3) throw new RuntimeException();
593     return 0;
594   }
595 
596   @Test
testMethodResolutionWithCxxTypes()597   public void testMethodResolutionWithCxxTypes() {
598     testMethodResolutionWithCxxTypesNative("methodResolutionWithCxxTypes", "test", 3);
599   }
600 
testMethodResolutionWithCxxTypesNative( String callbackName, String str, long val)601   private native void testMethodResolutionWithCxxTypesNative(
602       String callbackName, String str, long val);
603 
604   @Test(expected = CustomException.class)
testHandleJavaCustomException()605   public void testHandleJavaCustomException() {
606     testHandleJavaCustomExceptionNative();
607   }
608 
testHandleJavaCustomExceptionNative()609   private native void testHandleJavaCustomExceptionNative();
610 
611   @Test
testHandleNullExceptionMessage()612   public void testHandleNullExceptionMessage() {
613     testHandleNullExceptionMessageNative();
614   }
615 
testHandleNullExceptionMessageNative()616   private native void testHandleNullExceptionMessageNative();
617 
618   @Test
testHandleNestedException()619   public void testHandleNestedException() {
620     try {
621       nativeTestHandleNestedException();
622     } catch (Throwable e) {
623       assertThat(e).isInstanceOf(ArrayIndexOutOfBoundsException.class);
624       e = e.getCause();
625       assertThat(e).isInstanceOf(RuntimeException.class);
626       e = e.getCause();
627       assertThat(e).isInstanceOf(CustomException.class).hasNoCause();
628     }
629   }
630 
nativeTestHandleNestedException()631   private native void nativeTestHandleNestedException();
632 
633   @Test(expected = CppException.class)
testHandleNoRttiException()634   public void testHandleNoRttiException() {
635     nativeTestHandleNoRttiException();
636   }
637 
nativeTestHandleNoRttiException()638   private native void nativeTestHandleNoRttiException();
639 
640   @Test
testCopyConstructor()641   public void testCopyConstructor() {
642     assertThat(nativeTestCopyConstructor())
643         .startsWith(
644             "com.facebook.jni.FBJniTests$CustomException: getMessages: 1\n"
645                 + "\tat com.facebook.jni.FBJniTests.customExceptionThrower(FBJniTests.java:")
646         .contains(
647             ")\n"
648                 + "\tat com.facebook.jni.FBJniTests.nativeTestCopyConstructor(Native Method)\n"
649                 + "\tat com.facebook.jni.FBJniTests.testCopyConstructor(FBJniTests.java:");
650   }
651 
nativeTestCopyConstructor()652   private native String nativeTestCopyConstructor();
653 
654   @Test
testMoveConstructorWithEmptyWhat()655   public void testMoveConstructorWithEmptyWhat() {
656     assertThat(nativeTestMoveConstructorWithEmptyWhat())
657         .startsWith(
658             "com.facebook.jni.FBJniTests$CustomException: getMessages: 1\n"
659                 + "\tat com.facebook.jni.FBJniTests.customExceptionThrower(FBJniTests.java:")
660         .contains(
661             ")\n"
662                 + "\tat com.facebook.jni.FBJniTests.nativeTestMoveConstructorWithEmptyWhat(Native"
663                 + " Method)\n"
664                 + "\tat com.facebook.jni.FBJniTests.testMoveConstructorWithEmptyWhat(FBJniTests.java:");
665   }
666 
nativeTestMoveConstructorWithEmptyWhat()667   private native String nativeTestMoveConstructorWithEmptyWhat();
668 
669   @Test
testMoveConstructorWithPopulatedWhat()670   public void testMoveConstructorWithPopulatedWhat() {
671     assertThat(nativeTestMoveConstructorWithPopulatedWhat())
672         .startsWith(
673             "com.facebook.jni.FBJniTests$CustomException: getMessages: 1\n"
674                 + "\tat com.facebook.jni.FBJniTests.customExceptionThrower(FBJniTests.java:")
675         .contains(
676             ")\n"
677                 + "\tat com.facebook.jni.FBJniTests.nativeTestMoveConstructorWithPopulatedWhat(Native"
678                 + " Method)\n"
679                 + "\tat com.facebook.jni.FBJniTests.testMoveConstructorWithPopulatedWhat(FBJniTests.java:");
680   }
681 
nativeTestMoveConstructorWithPopulatedWhat()682   private native String nativeTestMoveConstructorWithPopulatedWhat();
683 
684   @DoNotStrip // Used in native code.
customExceptionThrower()685   protected void customExceptionThrower() throws CustomException {
686     throw new CustomException();
687   }
688 
689   @DoNotStrip // Used in native code.
nullMessageThrower()690   protected void nullMessageThrower() throws NullPointerException {
691     // just like Preconditions.checkNotNull() does
692     throw new NullPointerException();
693   }
694 
695   @Test
testHandleCppRuntimeError()696   public void testHandleCppRuntimeError() {
697     String message = "Sample runtime error.";
698     thrown.expect(RuntimeException.class);
699     thrown.expectMessage(message);
700     nativeTestHandleCppRuntimeError(message);
701   }
702 
nativeTestHandleCppRuntimeError(String message)703   private native void nativeTestHandleCppRuntimeError(String message);
704 
705   @Test(expected = IOException.class)
testHandleCppIOBaseFailure()706   public void testHandleCppIOBaseFailure() {
707     nativeTestHandleCppIOBaseFailure();
708   }
709 
nativeTestHandleCppIOBaseFailure()710   private native void nativeTestHandleCppIOBaseFailure();
711 
712   @Test(expected = CppSystemErrorException.class)
testHandleCppSystemError()713   public void testHandleCppSystemError() {
714     nativeTestHandleCppSystemError();
715   }
716 
nativeTestHandleCppSystemError()717   private native void nativeTestHandleCppSystemError();
718 
719   @Test(expected = RuntimeException.class)
testInterDsoExceptionHandlingA()720   public void testInterDsoExceptionHandlingA() {
721     nativeTestInterDsoExceptionHandlingA();
722   }
723 
nativeTestInterDsoExceptionHandlingA()724   private native void nativeTestInterDsoExceptionHandlingA();
725 
726   @Test
testInterDsoExceptionHandlingB()727   public void testInterDsoExceptionHandlingB() {
728     assertThat(nativeTestInterDsoExceptionHandlingB()).isTrue();
729   }
730 
nativeTestInterDsoExceptionHandlingB()731   private native boolean nativeTestInterDsoExceptionHandlingB();
732 
733   @Test
testHandleNonStdExceptionThrow()734   public void testHandleNonStdExceptionThrow() {
735     try {
736       nativeTestHandleNonStdExceptionThrow();
737       Fail.failBecauseExceptionWasNotThrown(UnknownCppException.class);
738     } catch (UnknownCppException ex) {
739       if (System.getProperty("os.name").startsWith("Windows")) {
740         // Unknown exception types not supported on Windows.
741         assertThat(ex.getMessage()).isEqualTo("Unknown");
742         return;
743       }
744       // the actual string is implementation-defined and mangled, but in practice,
745       // it has the name of the C++ type in it somewhere.
746       assertThat(ex.getMessage()).startsWith("Unknown: ").contains("NonStdException");
747     }
748   }
749 
nativeTestHandleNonStdExceptionThrow()750   private native void nativeTestHandleNonStdExceptionThrow();
751 
752   @Test(expected = UnknownCppException.class)
testHandleCppCharPointerThrow()753   public void testHandleCppCharPointerThrow() {
754     nativeTestHandleCppCharPointerThrow();
755   }
756 
nativeTestHandleCppCharPointerThrow()757   private native void nativeTestHandleCppCharPointerThrow();
758 
759   @Test(expected = IllegalArgumentException.class)
testThrowJavaExceptionByName()760   public void testThrowJavaExceptionByName() {
761     nativeTestThrowJavaExceptionByName();
762   }
763 
nativeTestThrowJavaExceptionByName()764   private native void nativeTestThrowJavaExceptionByName();
765 
766   @Test(expected = UnknownCppException.class)
testHandleCppIntThrow()767   public void testHandleCppIntThrow() {
768     nativeTestHandleCppIntThrow();
769   }
770 
nativeTestHandleCppIntThrow()771   private native void nativeTestHandleCppIntThrow();
772 
773   @Test
testJThread()774   public void testJThread() {
775     assertThat(nativeTestJThread()).isEqualTo(1);
776   }
777 
nativeTestJThread()778   private native int nativeTestJThread();
779 
780   @Test
testThreadScopeGuard()781   public void testThreadScopeGuard() {
782     assertThat(nativeTestThreadScopeGuard(17)).isEqualTo(42);
783   }
784 
nativeTestThreadScopeGuard(double input)785   private native int nativeTestThreadScopeGuard(double input);
786 
787   @Test
testNestedThreadScopeGuard()788   public void testNestedThreadScopeGuard() {
789     assertThat(nativeTestNestedThreadScopeGuard(17)).isEqualTo(42);
790   }
791 
nativeTestNestedThreadScopeGuard(double input)792   private native int nativeTestNestedThreadScopeGuard(double input);
793 
794   @Test
testClassLoadInWorker()795   public void testClassLoadInWorker() {
796     assertThat(nativeTestClassLoadInWorker()).isEqualTo(1);
797   }
798 
nativeTestClassLoadInWorker()799   private native int nativeTestClassLoadInWorker();
800 
801   @Test
testClassLoadWorkerFastPath()802   public void testClassLoadWorkerFastPath() {
803     assertThat(nativeTestClassLoadWorkerFastPath()).isEqualTo(3);
804   }
805 
nativeTestClassLoadWorkerFastPath()806   private native int nativeTestClassLoadWorkerFastPath();
807 
808   @Test
testToString()809   public void testToString() {
810     assertThat(nativeTestToString()).isTrue();
811   }
812 
nativeTestToString()813   private native boolean nativeTestToString();
814 
815   // Casting alias_ref
816 
817   @Test
testCorrectStaticCastAliasRef()818   public void testCorrectStaticCastAliasRef() {
819     // Static cast can't fail at run time.  If the object isn't actually
820     // of that type, we just get undefined behaviour, which we can't
821     // check for.  So we only do a positive test.
822     assertThat(nativeStaticCastAliasRefToString("hello")).isTrue();
823   }
824 
825   @Test
testNullStaticCastAliasRef()826   public void testNullStaticCastAliasRef() {
827     assertThat(nativeStaticCastAliasRefToString(null)).isTrue();
828   }
829 
nativeStaticCastAliasRefToString(Object a)830   private native boolean nativeStaticCastAliasRefToString(Object a);
831 
832   @Test
testDynamicCastAliasRefToSame()833   public void testDynamicCastAliasRefToSame() {
834     assertThat(nativeDynamicCastAliasRefToThrowable(new Throwable())).isTrue();
835   }
836 
testDynamicCastAliasRefToBase()837   public void testDynamicCastAliasRefToBase() {
838     assertThat(nativeDynamicCastAliasRefToThrowable(new Exception())).isTrue();
839   }
840 
841   @Test(expected = ClassCastException.class)
testDynamicCastAliasRefToDerived()842   public void testDynamicCastAliasRefToDerived() {
843     nativeDynamicCastAliasRefToThrowable(new Object());
844   }
845 
846   @Test(expected = ClassCastException.class)
testDynamicCastAliasRefToUnrelated()847   public void testDynamicCastAliasRefToUnrelated() {
848     nativeDynamicCastAliasRefToThrowable(new Integer(23));
849   }
850 
851   @Test
testNullDynamicCastAliasRef()852   public void testNullDynamicCastAliasRef() {
853     assertThat(nativeDynamicCastAliasRefToThrowable(null)).isTrue();
854   }
855 
nativeDynamicCastAliasRefToThrowable(Object a)856   private native boolean nativeDynamicCastAliasRefToThrowable(Object a);
857 
858   // Casting local_ref
859 
860   @Test
testCorrectStaticCastLocalRef()861   public void testCorrectStaticCastLocalRef() {
862     // Static cast can't fail at run time.  If the object isn't actually
863     // of that type, we just get undefined behaviour, which we can't
864     // check for.  So we only do a positive test.
865     assertThat(nativeStaticCastLocalRefToString("hello")).isTrue();
866   }
867 
868   @Test
testNullStaticCastLocalRef()869   public void testNullStaticCastLocalRef() {
870     assertThat(nativeStaticCastLocalRefToString(null)).isTrue();
871   }
872 
nativeStaticCastLocalRefToString(Object a)873   private native boolean nativeStaticCastLocalRefToString(Object a);
874 
875   @Test
testCorrectDynamicCastLocalRef()876   public void testCorrectDynamicCastLocalRef() {
877     assertThat(nativeDynamicCastLocalRefToString("hello")).isTrue();
878   }
879 
880   @Test(expected = ClassCastException.class)
testIncorrectDynamicCastLocalRef()881   public void testIncorrectDynamicCastLocalRef() {
882     nativeDynamicCastLocalRefToString(new Integer(23));
883   }
884 
885   @Test
testNullDynamicCastLocalRef()886   public void testNullDynamicCastLocalRef() {
887     assertThat(nativeDynamicCastLocalRefToString(null)).isTrue();
888   }
889 
nativeDynamicCastLocalRefToString(Object a)890   private native boolean nativeDynamicCastLocalRefToString(Object a);
891 
892   // Casting global_ref
893 
894   @Test
testCorrectStaticCastGlobalRef()895   public void testCorrectStaticCastGlobalRef() {
896     // Static cast can't fail at run time.  If the object isn't actually
897     // of that type, we just get undefined behaviour, which we can't
898     // check for.  So we only do a positive test.
899     assertThat(nativeStaticCastGlobalRefToString("hello")).isTrue();
900   }
901 
902   @Test
testNullStaticCastGlobalRef()903   public void testNullStaticCastGlobalRef() {
904     assertThat(nativeStaticCastGlobalRefToString(null)).isTrue();
905   }
906 
nativeStaticCastGlobalRefToString(Object a)907   private native boolean nativeStaticCastGlobalRefToString(Object a);
908 
909   @Test
testCorrectDynamicCastGlobalRef()910   public void testCorrectDynamicCastGlobalRef() {
911     assertThat(nativeDynamicCastGlobalRefToString("hello")).isTrue();
912   }
913 
914   @Test(expected = ClassCastException.class)
testIncorrectDynamicCastGlobalRef()915   public void testIncorrectDynamicCastGlobalRef() {
916     nativeDynamicCastGlobalRefToString(new Integer(23));
917   }
918 
919   @Test
testNullDynamicCastGlobalRef()920   public void testNullDynamicCastGlobalRef() {
921     assertThat(nativeDynamicCastGlobalRefToString(null)).isTrue();
922   }
923 
nativeDynamicCastGlobalRefToString(Object a)924   private native boolean nativeDynamicCastGlobalRefToString(Object a);
925 
926   @Test
testCriticalNativeMethodBindsAndCanBeInvoked()927   public void testCriticalNativeMethodBindsAndCanBeInvoked() {
928     assertThat(nativeCriticalNativeMethodBindsAndCanBeInvoked(12, 3.45f)).isTrue();
929   }
930 
nativeCriticalNativeMethodBindsAndCanBeInvoked(int a, float b)931   private static native boolean nativeCriticalNativeMethodBindsAndCanBeInvoked(int a, float b);
932 }
933