xref: /aosp_15_r20/libnativehelper/tests/libnativehelper_test.cpp (revision 0797b24ee566c78eb48500180cb4bf71f81c8aab)
1*0797b24eSAndroid Build Coastguard Worker /*
2*0797b24eSAndroid Build Coastguard Worker  * Copyright (C) 2024 The Android Open Source Project
3*0797b24eSAndroid Build Coastguard Worker  *
4*0797b24eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*0797b24eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*0797b24eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*0797b24eSAndroid Build Coastguard Worker  *
8*0797b24eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*0797b24eSAndroid Build Coastguard Worker  *
10*0797b24eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*0797b24eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*0797b24eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*0797b24eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*0797b24eSAndroid Build Coastguard Worker  * limitations under the License.
15*0797b24eSAndroid Build Coastguard Worker  */
16*0797b24eSAndroid Build Coastguard Worker 
17*0797b24eSAndroid Build Coastguard Worker #include <jni.h>
18*0797b24eSAndroid Build Coastguard Worker 
19*0797b24eSAndroid Build Coastguard Worker #include <memory>
20*0797b24eSAndroid Build Coastguard Worker 
21*0797b24eSAndroid Build Coastguard Worker #include "android-base/logging.h"
22*0797b24eSAndroid Build Coastguard Worker #include "gtest/gtest.h"
23*0797b24eSAndroid Build Coastguard Worker #include "nativehelper/scoped_local_ref.h"
24*0797b24eSAndroid Build Coastguard Worker #include "nativehelper/scoped_utf_chars.h"
25*0797b24eSAndroid Build Coastguard Worker #include "nativehelper/utils.h"
26*0797b24eSAndroid Build Coastguard Worker #include "nativetesthelper_jni/utils.h"
27*0797b24eSAndroid Build Coastguard Worker 
28*0797b24eSAndroid Build Coastguard Worker class LibnativehelperTest : public ::testing::Test {
29*0797b24eSAndroid Build Coastguard Worker    protected:
SetUp()30*0797b24eSAndroid Build Coastguard Worker     virtual void SetUp() override {
31*0797b24eSAndroid Build Coastguard Worker         int result = GetJavaVM()->GetEnv(reinterpret_cast<void**>(&mEnv), JNI_VERSION_1_6);
32*0797b24eSAndroid Build Coastguard Worker         CHECK_EQ(JNI_OK, result);
33*0797b24eSAndroid Build Coastguard Worker         CHECK_NE(nullptr, mEnv);
34*0797b24eSAndroid Build Coastguard Worker     }
35*0797b24eSAndroid Build Coastguard Worker 
TearDown()36*0797b24eSAndroid Build Coastguard Worker     virtual void TearDown() override { mEnv = nullptr; }
37*0797b24eSAndroid Build Coastguard Worker 
38*0797b24eSAndroid Build Coastguard Worker     JNIEnv* mEnv;
39*0797b24eSAndroid Build Coastguard Worker };
40*0797b24eSAndroid Build Coastguard Worker 
TEST_F(LibnativehelperTest,GetUtfOrReturn)41*0797b24eSAndroid Build Coastguard Worker TEST_F(LibnativehelperTest, GetUtfOrReturn) {
42*0797b24eSAndroid Build Coastguard Worker     ScopedLocalRef<jstring> j_str(mEnv, mEnv->NewStringUTF("foo"));
43*0797b24eSAndroid Build Coastguard Worker     std::unique_ptr<ScopedUtfChars> result;
44*0797b24eSAndroid Build Coastguard Worker 
45*0797b24eSAndroid Build Coastguard Worker     jint ret = [&](JNIEnv* env) -> jint {
46*0797b24eSAndroid Build Coastguard Worker         ScopedUtfChars str = GET_UTF_OR_RETURN(env, j_str.get());
47*0797b24eSAndroid Build Coastguard Worker         result.reset(new ScopedUtfChars(std::move(str)));
48*0797b24eSAndroid Build Coastguard Worker         return 1;
49*0797b24eSAndroid Build Coastguard Worker     }(mEnv);
50*0797b24eSAndroid Build Coastguard Worker 
51*0797b24eSAndroid Build Coastguard Worker     EXPECT_EQ(result->c_str(), std::string_view("foo"));
52*0797b24eSAndroid Build Coastguard Worker     EXPECT_FALSE(mEnv->ExceptionCheck());
53*0797b24eSAndroid Build Coastguard Worker     EXPECT_EQ(ret, 1);
54*0797b24eSAndroid Build Coastguard Worker }
55*0797b24eSAndroid Build Coastguard Worker 
TEST_F(LibnativehelperTest,GetUtfOrReturnVoid)56*0797b24eSAndroid Build Coastguard Worker TEST_F(LibnativehelperTest, GetUtfOrReturnVoid) {
57*0797b24eSAndroid Build Coastguard Worker     ScopedLocalRef<jstring> j_str(mEnv, mEnv->NewStringUTF("foo"));
58*0797b24eSAndroid Build Coastguard Worker     std::unique_ptr<ScopedUtfChars> result;
59*0797b24eSAndroid Build Coastguard Worker 
60*0797b24eSAndroid Build Coastguard Worker     [&](JNIEnv* env) -> void {
61*0797b24eSAndroid Build Coastguard Worker         ScopedUtfChars str = GET_UTF_OR_RETURN_VOID(env, j_str.get());
62*0797b24eSAndroid Build Coastguard Worker         result.reset(new ScopedUtfChars(std::move(str)));
63*0797b24eSAndroid Build Coastguard Worker     }(mEnv);
64*0797b24eSAndroid Build Coastguard Worker 
65*0797b24eSAndroid Build Coastguard Worker     EXPECT_EQ(result->c_str(), std::string_view("foo"));
66*0797b24eSAndroid Build Coastguard Worker     EXPECT_FALSE(mEnv->ExceptionCheck());
67*0797b24eSAndroid Build Coastguard Worker }
68*0797b24eSAndroid Build Coastguard Worker 
TEST_F(LibnativehelperTest,GetUtfOrReturnFailed)69*0797b24eSAndroid Build Coastguard Worker TEST_F(LibnativehelperTest, GetUtfOrReturnFailed) {
70*0797b24eSAndroid Build Coastguard Worker     jint ret = [&](JNIEnv* env) -> jint {
71*0797b24eSAndroid Build Coastguard Worker         ScopedUtfChars str = GET_UTF_OR_RETURN(env, nullptr);
72*0797b24eSAndroid Build Coastguard Worker         return 1;
73*0797b24eSAndroid Build Coastguard Worker     }(mEnv);
74*0797b24eSAndroid Build Coastguard Worker 
75*0797b24eSAndroid Build Coastguard Worker     EXPECT_TRUE(mEnv->ExceptionCheck());
76*0797b24eSAndroid Build Coastguard Worker     EXPECT_EQ(ret, 0);
77*0797b24eSAndroid Build Coastguard Worker 
78*0797b24eSAndroid Build Coastguard Worker     mEnv->ExceptionClear();
79*0797b24eSAndroid Build Coastguard Worker }
80*0797b24eSAndroid Build Coastguard Worker 
TEST_F(LibnativehelperTest,GetUtfOrReturnVoidFailed)81*0797b24eSAndroid Build Coastguard Worker TEST_F(LibnativehelperTest, GetUtfOrReturnVoidFailed) {
82*0797b24eSAndroid Build Coastguard Worker     bool execution_completed = false;
83*0797b24eSAndroid Build Coastguard Worker 
84*0797b24eSAndroid Build Coastguard Worker     [&](JNIEnv* env) -> void {
85*0797b24eSAndroid Build Coastguard Worker         ScopedUtfChars str = GET_UTF_OR_RETURN_VOID(env, nullptr);
86*0797b24eSAndroid Build Coastguard Worker         execution_completed = true;
87*0797b24eSAndroid Build Coastguard Worker     }(mEnv);
88*0797b24eSAndroid Build Coastguard Worker 
89*0797b24eSAndroid Build Coastguard Worker     EXPECT_TRUE(mEnv->ExceptionCheck());
90*0797b24eSAndroid Build Coastguard Worker     EXPECT_FALSE(execution_completed);
91*0797b24eSAndroid Build Coastguard Worker 
92*0797b24eSAndroid Build Coastguard Worker     mEnv->ExceptionClear();
93*0797b24eSAndroid Build Coastguard Worker }
94*0797b24eSAndroid Build Coastguard Worker 
TEST_F(LibnativehelperTest,CreateUtfOrReturn)95*0797b24eSAndroid Build Coastguard Worker TEST_F(LibnativehelperTest, CreateUtfOrReturn) {
96*0797b24eSAndroid Build Coastguard Worker     std::unique_ptr<ScopedLocalRef<jstring>> result;
97*0797b24eSAndroid Build Coastguard Worker 
98*0797b24eSAndroid Build Coastguard Worker     jint ret = [&](JNIEnv* env) -> jint {
99*0797b24eSAndroid Build Coastguard Worker         ScopedLocalRef<jstring> j_str = CREATE_UTF_OR_RETURN(env, "foo");
100*0797b24eSAndroid Build Coastguard Worker         result.reset(new ScopedLocalRef<jstring>(std::move(j_str)));
101*0797b24eSAndroid Build Coastguard Worker         return 1;
102*0797b24eSAndroid Build Coastguard Worker     }(mEnv);
103*0797b24eSAndroid Build Coastguard Worker 
104*0797b24eSAndroid Build Coastguard Worker     ScopedUtfChars str(mEnv, result->get());
105*0797b24eSAndroid Build Coastguard Worker     EXPECT_EQ(str.c_str(), std::string_view("foo"));
106*0797b24eSAndroid Build Coastguard Worker     EXPECT_FALSE(mEnv->ExceptionCheck());
107*0797b24eSAndroid Build Coastguard Worker     EXPECT_EQ(ret, 1);
108*0797b24eSAndroid Build Coastguard Worker }
109*0797b24eSAndroid Build Coastguard Worker 
110*0797b24eSAndroid Build Coastguard Worker class MyString : public std::string {
111*0797b24eSAndroid Build Coastguard Worker    public:
MyString(const char * c_str)112*0797b24eSAndroid Build Coastguard Worker     explicit MyString(const char* c_str) : std::string(c_str) {}
113*0797b24eSAndroid Build Coastguard Worker 
114*0797b24eSAndroid Build Coastguard Worker     // Force clear the string to catch use-after-free issues.
~MyString()115*0797b24eSAndroid Build Coastguard Worker     ~MyString() { clear(); }
116*0797b24eSAndroid Build Coastguard Worker };
117*0797b24eSAndroid Build Coastguard Worker 
118*0797b24eSAndroid Build Coastguard Worker // `expr` creates a temporary object and evaluates to it.
TEST_F(LibnativehelperTest,CreateUtfOrReturnExprEvaluatesToTemporary)119*0797b24eSAndroid Build Coastguard Worker TEST_F(LibnativehelperTest, CreateUtfOrReturnExprEvaluatesToTemporary) {
120*0797b24eSAndroid Build Coastguard Worker     std::unique_ptr<ScopedLocalRef<jstring>> result;
121*0797b24eSAndroid Build Coastguard Worker 
122*0797b24eSAndroid Build Coastguard Worker     jint ret = [&](JNIEnv* env) -> jint {
123*0797b24eSAndroid Build Coastguard Worker         ScopedLocalRef<jstring> j_str = CREATE_UTF_OR_RETURN(env, MyString("foo"));
124*0797b24eSAndroid Build Coastguard Worker         result.reset(new ScopedLocalRef<jstring>(std::move(j_str)));
125*0797b24eSAndroid Build Coastguard Worker         return 1;
126*0797b24eSAndroid Build Coastguard Worker     }(mEnv);
127*0797b24eSAndroid Build Coastguard Worker 
128*0797b24eSAndroid Build Coastguard Worker     ScopedUtfChars str(mEnv, result->get());
129*0797b24eSAndroid Build Coastguard Worker     EXPECT_EQ(str.c_str(), std::string_view("foo"));
130*0797b24eSAndroid Build Coastguard Worker     EXPECT_FALSE(mEnv->ExceptionCheck());
131*0797b24eSAndroid Build Coastguard Worker     EXPECT_EQ(ret, 1);
132*0797b24eSAndroid Build Coastguard Worker }
133*0797b24eSAndroid Build Coastguard Worker 
134*0797b24eSAndroid Build Coastguard Worker // `expr` creates a temporary object and evaluates to something else backed by it.
TEST_F(LibnativehelperTest,CreateUtfOrReturnExprEvaluatesToValueBackedByTemporary)135*0797b24eSAndroid Build Coastguard Worker TEST_F(LibnativehelperTest, CreateUtfOrReturnExprEvaluatesToValueBackedByTemporary) {
136*0797b24eSAndroid Build Coastguard Worker     std::unique_ptr<ScopedLocalRef<jstring>> result;
137*0797b24eSAndroid Build Coastguard Worker 
138*0797b24eSAndroid Build Coastguard Worker     jint ret = [&](JNIEnv* env) -> jint {
139*0797b24eSAndroid Build Coastguard Worker         ScopedLocalRef<jstring> j_str = CREATE_UTF_OR_RETURN(env, MyString("foo").c_str());
140*0797b24eSAndroid Build Coastguard Worker         result.reset(new ScopedLocalRef<jstring>(std::move(j_str)));
141*0797b24eSAndroid Build Coastguard Worker         return 1;
142*0797b24eSAndroid Build Coastguard Worker     }(mEnv);
143*0797b24eSAndroid Build Coastguard Worker 
144*0797b24eSAndroid Build Coastguard Worker     ScopedUtfChars str(mEnv, result->get());
145*0797b24eSAndroid Build Coastguard Worker     EXPECT_EQ(str.c_str(), std::string_view("foo"));
146*0797b24eSAndroid Build Coastguard Worker     EXPECT_FALSE(mEnv->ExceptionCheck());
147*0797b24eSAndroid Build Coastguard Worker     EXPECT_EQ(ret, 1);
148*0797b24eSAndroid Build Coastguard Worker }
149*0797b24eSAndroid Build Coastguard Worker 
TEST_F(LibnativehelperTest,CreateUtfOrReturnVoid)150*0797b24eSAndroid Build Coastguard Worker TEST_F(LibnativehelperTest, CreateUtfOrReturnVoid) {
151*0797b24eSAndroid Build Coastguard Worker     std::unique_ptr<ScopedLocalRef<jstring>> result;
152*0797b24eSAndroid Build Coastguard Worker 
153*0797b24eSAndroid Build Coastguard Worker     [&](JNIEnv* env) -> void {
154*0797b24eSAndroid Build Coastguard Worker         ScopedLocalRef<jstring> j_str = CREATE_UTF_OR_RETURN_VOID(env, "foo");
155*0797b24eSAndroid Build Coastguard Worker         result.reset(new ScopedLocalRef<jstring>(std::move(j_str)));
156*0797b24eSAndroid Build Coastguard Worker     }(mEnv);
157*0797b24eSAndroid Build Coastguard Worker 
158*0797b24eSAndroid Build Coastguard Worker     ScopedUtfChars str(mEnv, result->get());
159*0797b24eSAndroid Build Coastguard Worker     EXPECT_EQ(str.c_str(), std::string_view("foo"));
160*0797b24eSAndroid Build Coastguard Worker     EXPECT_FALSE(mEnv->ExceptionCheck());
161*0797b24eSAndroid Build Coastguard Worker }
162*0797b24eSAndroid Build Coastguard Worker 
TEST_F(LibnativehelperTest,CreateUtfOrReturnFailed)163*0797b24eSAndroid Build Coastguard Worker TEST_F(LibnativehelperTest, CreateUtfOrReturnFailed) {
164*0797b24eSAndroid Build Coastguard Worker     JNINativeInterface interface;
165*0797b24eSAndroid Build Coastguard Worker     interface.NewStringUTF = [](JNIEnv*, const char*) -> jstring { return nullptr; };
166*0797b24eSAndroid Build Coastguard Worker     JNIEnv fake_env;
167*0797b24eSAndroid Build Coastguard Worker     fake_env.functions = &interface;
168*0797b24eSAndroid Build Coastguard Worker 
169*0797b24eSAndroid Build Coastguard Worker     jint ret = [&](JNIEnv* env) -> jint {
170*0797b24eSAndroid Build Coastguard Worker         ScopedLocalRef<jstring> j_str = CREATE_UTF_OR_RETURN(env, "foo");
171*0797b24eSAndroid Build Coastguard Worker         return 1;
172*0797b24eSAndroid Build Coastguard Worker     }(&fake_env);
173*0797b24eSAndroid Build Coastguard Worker 
174*0797b24eSAndroid Build Coastguard Worker     EXPECT_EQ(ret, 0);
175*0797b24eSAndroid Build Coastguard Worker }
176*0797b24eSAndroid Build Coastguard Worker 
TEST_F(LibnativehelperTest,CreateUtfOrReturnVoidFailed)177*0797b24eSAndroid Build Coastguard Worker TEST_F(LibnativehelperTest, CreateUtfOrReturnVoidFailed) {
178*0797b24eSAndroid Build Coastguard Worker     JNINativeInterface interface;
179*0797b24eSAndroid Build Coastguard Worker     interface.NewStringUTF = [](JNIEnv*, const char*) -> jstring { return nullptr; };
180*0797b24eSAndroid Build Coastguard Worker     JNIEnv fake_env;
181*0797b24eSAndroid Build Coastguard Worker     fake_env.functions = &interface;
182*0797b24eSAndroid Build Coastguard Worker 
183*0797b24eSAndroid Build Coastguard Worker     bool execution_completed = false;
184*0797b24eSAndroid Build Coastguard Worker 
185*0797b24eSAndroid Build Coastguard Worker     [&](JNIEnv* env) -> void {
186*0797b24eSAndroid Build Coastguard Worker         ScopedLocalRef<jstring> j_str = CREATE_UTF_OR_RETURN_VOID(env, "foo");
187*0797b24eSAndroid Build Coastguard Worker         execution_completed = true;
188*0797b24eSAndroid Build Coastguard Worker     }(&fake_env);
189*0797b24eSAndroid Build Coastguard Worker 
190*0797b24eSAndroid Build Coastguard Worker     EXPECT_FALSE(execution_completed);
191*0797b24eSAndroid Build Coastguard Worker }
192