xref: /aosp_15_r20/external/fbjni/test/HybridTests.java (revision 65c59e023c5336bbd4a23be7af78407e3d80e7e7)
1*65c59e02SInna Palant /*
2*65c59e02SInna Palant  * Copyright (c) Facebook, Inc. and its affiliates.
3*65c59e02SInna Palant  *
4*65c59e02SInna Palant  * Licensed under the Apache License, Version 2.0 (the "License");
5*65c59e02SInna Palant  * you may not use this file except in compliance with the License.
6*65c59e02SInna Palant  * You may obtain a copy of the License at
7*65c59e02SInna Palant  *
8*65c59e02SInna Palant  *     http://www.apache.org/licenses/LICENSE-2.0
9*65c59e02SInna Palant  *
10*65c59e02SInna Palant  * Unless required by applicable law or agreed to in writing, software
11*65c59e02SInna Palant  * distributed under the License is distributed on an "AS IS" BASIS,
12*65c59e02SInna Palant  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*65c59e02SInna Palant  * See the License for the specific language governing permissions and
14*65c59e02SInna Palant  * limitations under the License.
15*65c59e02SInna Palant  */
16*65c59e02SInna Palant 
17*65c59e02SInna Palant package com.facebook.jni;
18*65c59e02SInna Palant 
19*65c59e02SInna Palant import static org.assertj.core.api.Assertions.assertThat;
20*65c59e02SInna Palant 
21*65c59e02SInna Palant import com.facebook.jni.annotations.DoNotStrip;
22*65c59e02SInna Palant import org.junit.Test;
23*65c59e02SInna Palant 
24*65c59e02SInna Palant public class HybridTests extends BaseFBJniTests {
25*65c59e02SInna Palant   static class TestHybridClass {
26*65c59e02SInna Palant     // Hybrid classes must include a member which manages the C++ object.  It
27*65c59e02SInna Palant     // will be initialized from C++.  It must be declared exactly with this
28*65c59e02SInna Palant     // type and name, so JNI can find it, and initialized once in the ctor.
29*65c59e02SInna Palant     // The annotation is necessary to keep proguard from renaming it, or else JNI
30*65c59e02SInna Palant     // won't be able to find it.
31*65c59e02SInna Palant     @DoNotStrip private final HybridData mHybridData;
32*65c59e02SInna Palant 
33*65c59e02SInna Palant     // This is the method which creates the C++ instance and initializes
34*65c59e02SInna Palant     // mHybridData.  Conventionally, it should be named initHybrid, and invoked
35*65c59e02SInna Palant     // from the constructor.  This must be called only once.  If the C++
36*65c59e02SInna Palant     // instance is referenced before this is called, a NullPointerException
37*65c59e02SInna Palant     // will be thrown.
initHybrid(int i, String s, boolean b)38*65c59e02SInna Palant     private native HybridData initHybrid(int i, String s, boolean b);
39*65c59e02SInna Palant 
40*65c59e02SInna Palant     // You can have more than one, which may be useful if the ctor is
41*65c59e02SInna Palant     // overloaded.  This will call the default C++ ctor.
initHybrid()42*65c59e02SInna Palant     private native HybridData initHybrid();
43*65c59e02SInna Palant 
44*65c59e02SInna Palant     // Implements factory-style initialization.  You shouldn't usually
45*65c59e02SInna Palant     // need both styles in one class.  Here we do it for testing and
46*65c59e02SInna Palant     // demo purposes.
initHybrid(String s, int i, boolean b)47*65c59e02SInna Palant     private native HybridData initHybrid(String s, int i, boolean b);
48*65c59e02SInna Palant 
49*65c59e02SInna Palant     // Java ctor must invoke initHybrid().  This just passes arguments through,
50*65c59e02SInna Palant     // but the ctor can do whatever work it wants, as long as it calls
51*65c59e02SInna Palant     // initHybrid() before any native methods.
TestHybridClass(int i, String s, boolean b)52*65c59e02SInna Palant     public TestHybridClass(int i, String s, boolean b) {
53*65c59e02SInna Palant       mHybridData = initHybrid(i, s, b);
54*65c59e02SInna Palant     }
55*65c59e02SInna Palant 
56*65c59e02SInna Palant     // This behaves the same as the ctor above, I just wanted a different
57*65c59e02SInna Palant     // signature to demonstrate factory-style initialization.
TestHybridClass(String s, int i, boolean b)58*65c59e02SInna Palant     public TestHybridClass(String s, int i, boolean b) {
59*65c59e02SInna Palant       mHybridData = initHybrid(s, i, b);
60*65c59e02SInna Palant     }
61*65c59e02SInna Palant 
62*65c59e02SInna Palant     // This is the simplest case.  Even if everything is default, initHybrid()
63*65c59e02SInna Palant     // must still be called.
TestHybridClass()64*65c59e02SInna Palant     public TestHybridClass() {
65*65c59e02SInna Palant       mHybridData = initHybrid();
66*65c59e02SInna Palant     }
67*65c59e02SInna Palant 
68*65c59e02SInna Palant     // Java ctor used by C++ newObjectCxxArgs.  Note this is private.
TestHybridClass(HybridData hd)69*65c59e02SInna Palant     private TestHybridClass(HybridData hd) {
70*65c59e02SInna Palant       mHybridData = hd;
71*65c59e02SInna Palant     }
72*65c59e02SInna Palant 
doneUsingIt()73*65c59e02SInna Palant     public void doneUsingIt() {
74*65c59e02SInna Palant       mHybridData.resetNative();
75*65c59e02SInna Palant     }
76*65c59e02SInna Palant 
77*65c59e02SInna Palant     // Some C++ methods.
setBoth(int i, String s)78*65c59e02SInna Palant     public native void setBoth(int i, String s);
79*65c59e02SInna Palant 
getInt()80*65c59e02SInna Palant     public native int getInt();
81*65c59e02SInna Palant 
getString()82*65c59e02SInna Palant     public native String getString();
83*65c59e02SInna Palant 
getCharString()84*65c59e02SInna Palant     public native String getCharString();
85*65c59e02SInna Palant 
copy1(TestHybridClass other)86*65c59e02SInna Palant     public native boolean copy1(TestHybridClass other);
87*65c59e02SInna Palant 
copy2(TestHybridClass other)88*65c59e02SInna Palant     public native boolean copy2(TestHybridClass other);
89*65c59e02SInna Palant 
oops()90*65c59e02SInna Palant     public native void oops();
91*65c59e02SInna Palant 
setGlobal(String s)92*65c59e02SInna Palant     public native void setGlobal(String s);
93*65c59e02SInna Palant 
getGlobal1()94*65c59e02SInna Palant     public native String getGlobal1();
95*65c59e02SInna Palant 
getGlobal2()96*65c59e02SInna Palant     public native String getGlobal2();
97*65c59e02SInna Palant 
makeWithTwo()98*65c59e02SInna Palant     public static native TestHybridClass makeWithTwo();
99*65c59e02SInna Palant 
makeWithThree()100*65c59e02SInna Palant     public static native TestHybridClass makeWithThree();
101*65c59e02SInna Palant 
autoconvertMany()102*65c59e02SInna Palant     public static native void autoconvertMany();
103*65c59e02SInna Palant   }
104*65c59e02SInna Palant 
105*65c59e02SInna Palant   @Test
testHybridClass()106*65c59e02SInna Palant   public void testHybridClass() {
107*65c59e02SInna Palant     TestHybridClass thc1 = new TestHybridClass();
108*65c59e02SInna Palant     assertThat(thc1.getInt()).isEqualTo(0);
109*65c59e02SInna Palant     assertThat(thc1.getString()).isEqualTo("");
110*65c59e02SInna Palant 
111*65c59e02SInna Palant     thc1.setBoth(1, "one");
112*65c59e02SInna Palant     assertThat(thc1.getInt()).isEqualTo(1);
113*65c59e02SInna Palant     assertThat(thc1.getString()).isEqualTo("one");
114*65c59e02SInna Palant 
115*65c59e02SInna Palant     TestHybridClass thc2 = TestHybridClass.makeWithTwo();
116*65c59e02SInna Palant     assertThat(thc2.getInt()).isEqualTo(2);
117*65c59e02SInna Palant     assertThat(thc2.getString()).isEqualTo("two");
118*65c59e02SInna Palant 
119*65c59e02SInna Palant     thc2.doneUsingIt();
120*65c59e02SInna Palant 
121*65c59e02SInna Palant     thrown.expect(NullPointerException.class);
122*65c59e02SInna Palant     thc2.getInt();
123*65c59e02SInna Palant   }
124*65c59e02SInna Palant 
125*65c59e02SInna Palant   @Test
testHybridAutoconversion()126*65c59e02SInna Palant   public void testHybridAutoconversion() {
127*65c59e02SInna Palant     TestHybridClass thc3 = TestHybridClass.makeWithThree();
128*65c59e02SInna Palant     assertThat(thc3.copy1(new TestHybridClass(3, "three", false))).isTrue();
129*65c59e02SInna Palant     assertThat(thc3.getInt()).isEqualTo(3);
130*65c59e02SInna Palant     assertThat(thc3.getString()).isEqualTo("three");
131*65c59e02SInna Palant 
132*65c59e02SInna Palant     TestHybridClass thc4 = new TestHybridClass();
133*65c59e02SInna Palant     thc4.copy1(new TestHybridClass("four", 4, false));
134*65c59e02SInna Palant     assertThat(thc4.getInt()).isEqualTo(4);
135*65c59e02SInna Palant     assertThat(thc4.getString()).isEqualTo("four");
136*65c59e02SInna Palant     assertThat(thc4.getCharString()).isEqualTo("four");
137*65c59e02SInna Palant 
138*65c59e02SInna Palant     TestHybridClass thc5 = new TestHybridClass();
139*65c59e02SInna Palant     assertThat(thc5.copy2(new TestHybridClass(5, "five", false))).isTrue();
140*65c59e02SInna Palant     assertThat(thc5.getInt()).isEqualTo(5);
141*65c59e02SInna Palant     assertThat(thc5.getString()).isEqualTo("five");
142*65c59e02SInna Palant   }
143*65c59e02SInna Palant 
144*65c59e02SInna Palant   @Test
testReturnGlobalRef()145*65c59e02SInna Palant   public void testReturnGlobalRef() {
146*65c59e02SInna Palant     TestHybridClass thc = new TestHybridClass();
147*65c59e02SInna Palant     thc.setGlobal("global_ref");
148*65c59e02SInna Palant     assertThat(thc.getGlobal1()).isEqualTo("global_ref");
149*65c59e02SInna Palant     assertThat(thc.getGlobal2()).isEqualTo("global_ref");
150*65c59e02SInna Palant   }
151*65c59e02SInna Palant 
152*65c59e02SInna Palant   @Test
testLocalLeak()153*65c59e02SInna Palant   public void testLocalLeak() {
154*65c59e02SInna Palant     TestHybridClass.autoconvertMany();
155*65c59e02SInna Palant   }
156*65c59e02SInna Palant 
157*65c59e02SInna Palant   @Test
testExceptionMapping()158*65c59e02SInna Palant   public void testExceptionMapping() {
159*65c59e02SInna Palant     TestHybridClass thc1 = new TestHybridClass();
160*65c59e02SInna Palant     thrown.expect(ArrayStoreException.class);
161*65c59e02SInna Palant     thc1.oops();
162*65c59e02SInna Palant   }
163*65c59e02SInna Palant 
164*65c59e02SInna Palant   abstract static class AbstractTestHybrid {
165*65c59e02SInna Palant     @DoNotStrip private final HybridData mHybridData;
166*65c59e02SInna Palant 
167*65c59e02SInna Palant     private int mAbstractNum;
168*65c59e02SInna Palant 
AbstractTestHybrid(HybridData hybridData, int an)169*65c59e02SInna Palant     protected AbstractTestHybrid(HybridData hybridData, int an) {
170*65c59e02SInna Palant       mHybridData = hybridData;
171*65c59e02SInna Palant       mAbstractNum = an;
172*65c59e02SInna Palant     }
173*65c59e02SInna Palant 
abstractNum()174*65c59e02SInna Palant     public int abstractNum() {
175*65c59e02SInna Palant       return mAbstractNum;
176*65c59e02SInna Palant     }
177*65c59e02SInna Palant 
nativeNum()178*65c59e02SInna Palant     public native int nativeNum();
179*65c59e02SInna Palant 
concreteNum()180*65c59e02SInna Palant     public abstract int concreteNum();
181*65c59e02SInna Palant 
sum()182*65c59e02SInna Palant     public abstract int sum();
183*65c59e02SInna Palant   }
184*65c59e02SInna Palant 
185*65c59e02SInna Palant   static class ConcreteTestHybrid extends AbstractTestHybrid {
ConcreteTestHybrid(int an, int nn, int cn)186*65c59e02SInna Palant     public ConcreteTestHybrid(int an, int nn, int cn) {
187*65c59e02SInna Palant       super(initHybrid(nn, cn), an);
188*65c59e02SInna Palant     }
189*65c59e02SInna Palant 
initHybrid(int nn, int cn)190*65c59e02SInna Palant     private static native HybridData initHybrid(int nn, int cn);
191*65c59e02SInna Palant 
192*65c59e02SInna Palant     // overrides can be native
193*65c59e02SInna Palant     @Override
concreteNum()194*65c59e02SInna Palant     public native int concreteNum();
195*65c59e02SInna Palant 
196*65c59e02SInna Palant     // overrides can be java
197*65c59e02SInna Palant     @Override
sum()198*65c59e02SInna Palant     public int sum() {
199*65c59e02SInna Palant       return nativeNum() + abstractNum() + concreteNum();
200*65c59e02SInna Palant     }
201*65c59e02SInna Palant   }
202*65c59e02SInna Palant 
203*65c59e02SInna Palant   @Test
testHybridInheritance()204*65c59e02SInna Palant   public void testHybridInheritance() {
205*65c59e02SInna Palant     AbstractTestHybrid ath = new ConcreteTestHybrid(1, 2, 3);
206*65c59e02SInna Palant     assertThat(ath.abstractNum()).isEqualTo(1);
207*65c59e02SInna Palant     assertThat(ath.nativeNum()).isEqualTo(2);
208*65c59e02SInna Palant     assertThat(ath.concreteNum()).isEqualTo(3);
209*65c59e02SInna Palant     assertThat(ath.sum()).isEqualTo(6);
210*65c59e02SInna Palant   }
211*65c59e02SInna Palant 
cxxTestInheritance(AbstractTestHybrid ath)212*65c59e02SInna Palant   public static native boolean cxxTestInheritance(AbstractTestHybrid ath);
213*65c59e02SInna Palant 
makeAbstractHybrid()214*65c59e02SInna Palant   public static native AbstractTestHybrid makeAbstractHybrid();
215*65c59e02SInna Palant 
216*65c59e02SInna Palant   @Test
testHybridCxx()217*65c59e02SInna Palant   public void testHybridCxx() {
218*65c59e02SInna Palant     AbstractTestHybrid ath = new ConcreteTestHybrid(4, 5, 6);
219*65c59e02SInna Palant     assertThat(cxxTestInheritance(ath)).isTrue();
220*65c59e02SInna Palant 
221*65c59e02SInna Palant     AbstractTestHybrid ath2 = makeAbstractHybrid();
222*65c59e02SInna Palant     assertThat(ath2 instanceof ConcreteTestHybrid).isTrue();
223*65c59e02SInna Palant     assertThat(ath2.abstractNum()).isEqualTo(7);
224*65c59e02SInna Palant     assertThat(ath2.nativeNum()).isEqualTo(8);
225*65c59e02SInna Palant     assertThat(ath2.concreteNum()).isEqualTo(9);
226*65c59e02SInna Palant     assertThat(ath2.sum()).isEqualTo(24);
227*65c59e02SInna Palant   }
228*65c59e02SInna Palant 
229*65c59e02SInna Palant   static class Base {}
230*65c59e02SInna Palant 
231*65c59e02SInna Palant   static class Derived extends Base {
232*65c59e02SInna Palant     @DoNotStrip private final HybridData mHybridData;
233*65c59e02SInna Palant 
Derived(HybridData hybridData)234*65c59e02SInna Palant     private Derived(HybridData hybridData) {
235*65c59e02SInna Palant       mHybridData = hybridData;
236*65c59e02SInna Palant     }
237*65c59e02SInna Palant   }
238*65c59e02SInna Palant 
cxxTestDerivedJavaClass()239*65c59e02SInna Palant   public static native boolean cxxTestDerivedJavaClass();
240*65c59e02SInna Palant 
241*65c59e02SInna Palant   @Test
testDerivedJavaClassCxx()242*65c59e02SInna Palant   public void testDerivedJavaClassCxx() {
243*65c59e02SInna Palant     assertThat(cxxTestDerivedJavaClass()).isTrue();
244*65c59e02SInna Palant   }
245*65c59e02SInna Palant 
246*65c59e02SInna Palant   static class TestHybridClassBase extends HybridClassBase {
initHybrid()247*65c59e02SInna Palant     protected native void initHybrid();
248*65c59e02SInna Palant 
initHybrid(int i)249*65c59e02SInna Palant     private native void initHybrid(int i);
250*65c59e02SInna Palant 
TestHybridClassBase()251*65c59e02SInna Palant     protected TestHybridClassBase() {
252*65c59e02SInna Palant       // No initHybrid() here!
253*65c59e02SInna Palant       // Otherwise factory construction will set native pointer twice and process will crash.
254*65c59e02SInna Palant     }
255*65c59e02SInna Palant 
TestHybridClassBase(int i)256*65c59e02SInna Palant     public TestHybridClassBase(int i) {
257*65c59e02SInna Palant       initHybrid(i);
258*65c59e02SInna Palant     }
259*65c59e02SInna Palant 
260*65c59e02SInna Palant     // Some C++ methods.
setInt(int i)261*65c59e02SInna Palant     public native void setInt(int i);
262*65c59e02SInna Palant 
getInt()263*65c59e02SInna Palant     public native int getInt();
264*65c59e02SInna Palant 
makeWithThree()265*65c59e02SInna Palant     public static native TestHybridClassBase makeWithThree();
266*65c59e02SInna Palant   }
267*65c59e02SInna Palant 
268*65c59e02SInna Palant   static class TestHybridClassBaseDefaultCtor extends TestHybridClassBase {
TestHybridClassBaseDefaultCtor()269*65c59e02SInna Palant     public TestHybridClassBaseDefaultCtor() {
270*65c59e02SInna Palant       initHybrid();
271*65c59e02SInna Palant     }
272*65c59e02SInna Palant   }
273*65c59e02SInna Palant 
274*65c59e02SInna Palant   @Test
testHybridBaseDefaultCtor()275*65c59e02SInna Palant   public void testHybridBaseDefaultCtor() {
276*65c59e02SInna Palant     TestHybridClassBaseDefaultCtor base = new TestHybridClassBaseDefaultCtor();
277*65c59e02SInna Palant     assertThat(base.getInt()).isZero();
278*65c59e02SInna Palant 
279*65c59e02SInna Palant     base.setInt(58);
280*65c59e02SInna Palant     assertThat(base.getInt()).isEqualTo(58);
281*65c59e02SInna Palant   }
282*65c59e02SInna Palant 
283*65c59e02SInna Palant   @Test
testHybridBaseConstructorArgs()284*65c59e02SInna Palant   public void testHybridBaseConstructorArgs() {
285*65c59e02SInna Palant     TestHybridClassBase base = new TestHybridClassBase(42);
286*65c59e02SInna Palant     assertThat(base.getInt()).isEqualTo(42);
287*65c59e02SInna Palant   }
288*65c59e02SInna Palant 
289*65c59e02SInna Palant   @Test
testHybridBaseFactoryConstruction()290*65c59e02SInna Palant   public void testHybridBaseFactoryConstruction() {
291*65c59e02SInna Palant     TestHybridClassBase base = TestHybridClassBase.makeWithThree();
292*65c59e02SInna Palant     assertThat(base.getInt()).isEqualTo(3);
293*65c59e02SInna Palant   }
294*65c59e02SInna Palant 
295*65c59e02SInna Palant   static class Destroyable {
296*65c59e02SInna Palant     @DoNotStrip private final HybridData mHybridData;
297*65c59e02SInna Palant 
Destroyable(HybridData hybridData)298*65c59e02SInna Palant     private Destroyable(HybridData hybridData) {
299*65c59e02SInna Palant       mHybridData = hybridData;
300*65c59e02SInna Palant     }
301*65c59e02SInna Palant   }
302*65c59e02SInna Palant 
cxxTestHybridDestruction()303*65c59e02SInna Palant   public static native boolean cxxTestHybridDestruction();
304*65c59e02SInna Palant 
305*65c59e02SInna Palant   @Test
testHybridDestuction()306*65c59e02SInna Palant   public void testHybridDestuction() {
307*65c59e02SInna Palant     assertThat(cxxTestHybridDestruction()).isTrue();
308*65c59e02SInna Palant   }
309*65c59e02SInna Palant }
310