Skip to content

Commit 7889019

Browse files
authored
Merge 84400cf into b1a5444
2 parents b1a5444 + 84400cf commit 7889019

21 files changed

+635
-66
lines changed

firestore/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ set(android_SRCS
138138
src/android/wrapper.h
139139
src/android/write_batch_android.cc
140140
src/android/write_batch_android.h
141+
src/jni/arena_ref.cc
142+
src/jni/arena_ref.h
141143
src/jni/array.h
142144
src/jni/array_list.cc
143145
src/jni/array_list.h

firestore/integration_test_internal/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ set(FIREBASE_INTEGRATION_TEST_ANDROID_TEST_SRCS
131131
src/android/snapshot_metadata_android_test.cc
132132
src/android/timestamp_android_test.cc
133133
src/android/transaction_options_android_test.cc
134+
src/jni/arena_ref_test.cc
134135
src/jni/declaration_test.cc
135136
src/jni/env_test.cc
136137
src/jni/object_test.cc

firestore/integration_test_internal/src/document_reference_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ TEST_F(DocumentReferenceTest, RecoverFirestore) {
5959
DocumentReference doc = Document();
6060
ASSERT_EQ(db, doc.firestore()); // Sanity check
6161

62-
jni::Object doc_java = GetInternal(doc)->ToJava();
62+
jni::Local<jni::Object> doc_java = GetInternal(doc)->ToJava();
6363
result = DocumentReferenceInternal::Create(env, doc_java);
6464
ASSERT_EQ(db, result.firestore());
6565
}

firestore/integration_test_internal/src/field_value_test.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,5 +367,12 @@ TEST_F(FieldValueTest, TestIncrementChoosesTheCorrectType) {
367367
// clang-format on
368368
}
369369

370+
TEST_F(FieldValueTest, TestArenaRefMinimunLimit) {
371+
std::vector<FieldValue> numbers;
372+
for (size_t i = 0U; i < 60000; i++) {
373+
numbers.push_back(FieldValue::Integer(i));
374+
}
375+
}
376+
370377
} // namespace firestore
371378
} // namespace firebase
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
/*
2+
* Copyright 2023 Google LLC
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+
#include "firestore/src/jni/arena_ref.h"
18+
#include "firestore/src/android/firestore_android.h"
19+
#include "firestore/src/common/make_unique.h"
20+
#include "firestore/src/jni/loader.h"
21+
#include "firestore/src/jni/long.h"
22+
23+
#include "firestore_integration_test.h"
24+
25+
#include "gtest/gtest.h"
26+
27+
namespace firebase {
28+
namespace firestore {
29+
namespace jni {
30+
namespace {
31+
32+
constexpr char kException[] = "java/lang/Exception";
33+
Method<String> kConstructor("<init>", "(Ljava/lang/String;)V");
34+
35+
class ArenaRefTestAndroid : public FirestoreIntegrationTest {
36+
public:
37+
ArenaRefTestAndroid() : loader_(app()), env_(make_unique<Env>(GetEnv())) {
38+
loader_.LoadClass(kException);
39+
loader_.Load(kConstructor);
40+
}
41+
42+
~ArenaRefTestAndroid() override {
43+
// Ensure that after the test is done that any pending exception is cleared
44+
// to prevent spurious errors in the teardown of FirestoreIntegrationTest.
45+
env_->ExceptionClear();
46+
}
47+
48+
Env& env() const { return *env_; }
49+
50+
void throwException() {
51+
Local<Class> clazz = env().FindClass(kException);
52+
jmethodID ctor =
53+
env().GetMethodId(clazz, "<init>", "(Ljava/lang/String;)V");
54+
55+
Local<String> message = env().NewStringUtf("Testing throw");
56+
Local<Throwable> exception = env().New<Throwable>(clazz, ctor, message);
57+
// After throwing, use EXPECT rather than ASSERT to ensure that the
58+
// exception is cleared.
59+
env().Throw(exception);
60+
EXPECT_FALSE(env().ok());
61+
}
62+
63+
void clearExceptionOccurred() {
64+
Local<Throwable> thrown = env().ClearExceptionOccurred();
65+
EXPECT_EQ(thrown.GetMessage(env()), "Testing throw");
66+
}
67+
68+
private:
69+
// Env is declared as having a `noexcept(false)` destructor, which causes the
70+
// compiler to propagate this into `EnvTest`'s destructor, but this conflicts
71+
// with the declaration of the parent class. Holding `Env` with a unique
72+
// pointer sidesteps this restriction.
73+
std::unique_ptr<Env> env_;
74+
Loader loader_;
75+
};
76+
77+
TEST_F(ArenaRefTestAndroid, DefaultConstructor) {
78+
ArenaRef arena_ref;
79+
EXPECT_EQ(arena_ref.get(env()).get(), nullptr);
80+
}
81+
82+
TEST_F(ArenaRefTestAndroid, ConstructsFromNull) {
83+
Local<String> string;
84+
ArenaRef arena_ref(env(), string);
85+
EXPECT_EQ(arena_ref.get(env()).get(), nullptr);
86+
}
87+
88+
TEST_F(ArenaRefTestAndroid, ConstructsFromValid) {
89+
Local<String> string = env().NewStringUtf("hello world");
90+
ArenaRef arena_ref(env(), string);
91+
EXPECT_TRUE(env().IsSameObject(arena_ref.get(env()), string));
92+
}
93+
94+
TEST_F(ArenaRefTestAndroid, CopyConstructsFromNull) {
95+
ArenaRef arena_ref1;
96+
ArenaRef arena_ref2(arena_ref1);
97+
EXPECT_EQ(arena_ref2.get(env()).get(), nullptr);
98+
}
99+
100+
TEST_F(ArenaRefTestAndroid, CopyConstructsFromValid) {
101+
Local<String> string = env().NewStringUtf("hello world");
102+
103+
ArenaRef arena_ref1(env(), string);
104+
ArenaRef arena_ref2(arena_ref1);
105+
EXPECT_TRUE(env().IsSameObject(arena_ref1.get(env()), string));
106+
EXPECT_TRUE(env().IsSameObject(arena_ref2.get(env()), string));
107+
}
108+
109+
TEST_F(ArenaRefTestAndroid, CopyAssignsFromNullToNull) {
110+
ArenaRef arena_ref1, arena_ref2;
111+
arena_ref2 = arena_ref1;
112+
EXPECT_EQ(arena_ref1.get(env()).get(), nullptr);
113+
EXPECT_EQ(arena_ref2.get(env()).get(), nullptr);
114+
}
115+
116+
TEST_F(ArenaRefTestAndroid, CopyAssignsFromNullToValid) {
117+
Local<String> string = env().NewStringUtf("hello world");
118+
119+
ArenaRef arena_ref1;
120+
ArenaRef arena_ref2(env(), string);
121+
arena_ref2 = arena_ref1;
122+
EXPECT_EQ(arena_ref1.get(env()).get(), nullptr);
123+
EXPECT_EQ(arena_ref2.get(env()).get(), nullptr);
124+
}
125+
126+
TEST_F(ArenaRefTestAndroid, CopyAssignsFromValidToNull) {
127+
Local<String> string = env().NewStringUtf("hello world");
128+
129+
ArenaRef arena_ref1;
130+
ArenaRef arena_ref2(env(), string);
131+
arena_ref1 = arena_ref2;
132+
EXPECT_TRUE(env().IsSameObject(arena_ref1.get(env()), string));
133+
EXPECT_TRUE(env().IsSameObject(arena_ref2.get(env()), string));
134+
}
135+
136+
TEST_F(ArenaRefTestAndroid, CopyAssignsFromValidToValid) {
137+
Local<String> string1 = env().NewStringUtf("hello world");
138+
Local<String> string2 = env().NewStringUtf("hello earth");
139+
140+
ArenaRef arena_ref1(env(), string1);
141+
ArenaRef arena_ref2(env(), string2);
142+
arena_ref1 = arena_ref2;
143+
144+
EXPECT_TRUE(env().IsSameObject(arena_ref1.get(env()), string2));
145+
EXPECT_TRUE(env().IsSameObject(arena_ref2.get(env()), string2));
146+
}
147+
148+
TEST_F(ArenaRefTestAndroid, CopyAssignsFromNullObjectItself) {
149+
ArenaRef arena_ref1;
150+
arena_ref1 = arena_ref1;
151+
EXPECT_EQ(arena_ref1.get(env()).get(), nullptr);
152+
}
153+
154+
TEST_F(ArenaRefTestAndroid, CopyAssignsFromValidObjectItself) {
155+
Local<String> string1 = env().NewStringUtf("hello world");
156+
157+
ArenaRef arena_ref1(env(), string1);
158+
arena_ref1 = arena_ref1;
159+
EXPECT_TRUE(env().IsSameObject(arena_ref1.get(env()), string1));
160+
}
161+
162+
TEST_F(ArenaRefTestAndroid, MoveConstructsFromNull) {
163+
ArenaRef arena_ref1;
164+
ArenaRef arena_ref2(std::move(arena_ref1));
165+
EXPECT_EQ(arena_ref2.get(env()).get(), nullptr);
166+
}
167+
168+
TEST_F(ArenaRefTestAndroid, MoveConstructsFromValid) {
169+
Local<String> string = env().NewStringUtf("hello world");
170+
171+
ArenaRef arena_ref2(env(), string);
172+
ArenaRef arena_ref3(std::move(arena_ref2));
173+
EXPECT_TRUE(env().IsSameObject(arena_ref3.get(env()), string));
174+
}
175+
176+
TEST_F(ArenaRefTestAndroid, MoveAssignsFromNullToNull) {
177+
ArenaRef arena_ref1, arena_ref2;
178+
arena_ref2 = std::move(arena_ref1);
179+
EXPECT_EQ(arena_ref2.get(env()).get(), nullptr);
180+
}
181+
182+
TEST_F(ArenaRefTestAndroid, MoveAssignsFromNullToValid) {
183+
Local<String> string = env().NewStringUtf("hello world");
184+
185+
ArenaRef arena_ref1;
186+
ArenaRef arena_ref2(env(), string);
187+
arena_ref2 = std::move(arena_ref1);
188+
EXPECT_EQ(arena_ref2.get(env()).get(), nullptr);
189+
}
190+
191+
TEST_F(ArenaRefTestAndroid, MoveAssignsFromValidToNull) {
192+
Local<String> string = env().NewStringUtf("hello world");
193+
194+
ArenaRef arena_ref1;
195+
ArenaRef arena_ref2(env(), string);
196+
arena_ref1 = std::move(arena_ref2);
197+
EXPECT_TRUE(env().IsSameObject(arena_ref1.get(env()), string));
198+
}
199+
200+
TEST_F(ArenaRefTestAndroid, MoveAssignsFromValidToValid) {
201+
Local<String> string1 = env().NewStringUtf("hello world");
202+
Local<String> string2 = env().NewStringUtf("hello earth");
203+
204+
ArenaRef arena_ref1(env(), string1);
205+
ArenaRef arena_ref2(env(), string2);
206+
arena_ref1 = std::move(arena_ref2);
207+
EXPECT_TRUE(env().IsSameObject(arena_ref1.get(env()), string2));
208+
}
209+
210+
TEST_F(ArenaRefTestAndroid, MoveAssignsFromNullObjectItself) {
211+
ArenaRef arena_ref1;
212+
arena_ref1 = std::move(arena_ref1);
213+
EXPECT_EQ(arena_ref1.get(env()).get(), nullptr);
214+
}
215+
216+
TEST_F(ArenaRefTestAndroid, MoveAssignsFromValidObjectItself) {
217+
Local<String> string1 = env().NewStringUtf("hello world");
218+
219+
ArenaRef arena_ref1(env(), string1);
220+
arena_ref1 = std::move(arena_ref1);
221+
EXPECT_TRUE(env().IsSameObject(arena_ref1.get(env()), string1));
222+
}
223+
224+
TEST_F(ArenaRefTestAndroid, ThrowBeforeConstruct) {
225+
Local<String> string = env().NewStringUtf("hello world");
226+
EXPECT_EQ(string.ToString(env()).size(), 11U);
227+
throwException();
228+
ArenaRef arena_ref(env(), string);
229+
clearExceptionOccurred();
230+
EXPECT_EQ(arena_ref.get(env()).get(), nullptr);
231+
}
232+
233+
TEST_F(ArenaRefTestAndroid, ThrowBeforeCopyConstruct) {
234+
Local<String> string = env().NewStringUtf("hello world");
235+
ArenaRef arena_ref1(env(), string);
236+
EXPECT_EQ(arena_ref1.get(env()).ToString(env()).size(), 11U);
237+
throwException();
238+
ArenaRef arena_ref2(arena_ref1);
239+
clearExceptionOccurred();
240+
EXPECT_EQ(arena_ref2.get(env()).get(), nullptr);
241+
}
242+
243+
TEST_F(ArenaRefTestAndroid, ThrowBeforeCopyAssignment) {
244+
Local<String> string = env().NewStringUtf("hello world");
245+
ArenaRef arena_ref1(env(), string);
246+
ArenaRef arena_ref2;
247+
EXPECT_EQ(arena_ref1.get(env()).ToString(env()).size(), 11U);
248+
throwException();
249+
arena_ref2 = arena_ref1;
250+
clearExceptionOccurred();
251+
EXPECT_EQ(arena_ref2.get(env()).get(), nullptr);
252+
}
253+
254+
TEST_F(ArenaRefTestAndroid, ThrowBeforeMoveConstruct) {
255+
Local<String> string = env().NewStringUtf("hello world");
256+
ArenaRef arena_ref1(env(), string);
257+
EXPECT_EQ(arena_ref1.get(env()).ToString(env()).size(), 11U);
258+
throwException();
259+
ArenaRef arena_ref2(std::move(arena_ref1));
260+
clearExceptionOccurred();
261+
EXPECT_TRUE(env().IsSameObject(arena_ref2.get(env()), string));
262+
}
263+
264+
TEST_F(ArenaRefTestAndroid, ThrowBeforeMoveAssignment) {
265+
Local<String> string = env().NewStringUtf("hello world");
266+
ArenaRef arena_ref1(env(), string);
267+
ArenaRef arena_ref2;
268+
EXPECT_EQ(arena_ref1.get(env()).ToString(env()).size(), 11U);
269+
throwException();
270+
arena_ref2 = std::move(arena_ref1);
271+
clearExceptionOccurred();
272+
EXPECT_TRUE(env().IsSameObject(arena_ref2.get(env()), string));
273+
}
274+
275+
} // namespace
276+
} // namespace jni
277+
} // namespace firestore
278+
} // namespace firebase

firestore/integration_test_internal/src/jni/env_test.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,18 @@ TEST_F(EnvTest, CallsVoidMethods) {
128128
EXPECT_EQ(length, 42);
129129
}
130130

131+
TEST_F(EnvTest, CallsValidArenaRef) {
132+
Local<String> str = env().NewStringUtf("Foo");
133+
ArenaRef arena_ref(env(), str);
134+
135+
Local<Class> clazz = env().FindClass("java/lang/String");
136+
jmethodID to_lower_case =
137+
env().GetMethodId(clazz, "toLowerCase", "()Ljava/lang/String;");
138+
139+
Local<Object> result = env().Call(arena_ref, Method<Object>(to_lower_case));
140+
EXPECT_EQ("foo", result.ToString(env()));
141+
}
142+
131143
TEST_F(EnvTest, GetsStaticFields) {
132144
Local<Class> clazz = env().FindClass("java/lang/String");
133145
jfieldID comparator = env().GetStaticFieldId(clazz, "CASE_INSENSITIVE_ORDER",
@@ -160,6 +172,21 @@ TEST_F(EnvTest, ToString) {
160172
EXPECT_EQ("Foo", result);
161173
}
162174

175+
TEST_F(EnvTest, IsInstanceOfChecksValidArenaRef) {
176+
Local<Class> clazz = env().FindClass("java/lang/String");
177+
Local<String> str = env().NewStringUtf("Foo");
178+
ArenaRef arena_ref(env(), str);
179+
EXPECT_TRUE(env().IsInstanceOf(arena_ref, clazz));
180+
}
181+
182+
TEST_F(EnvTest, IsInstanceOfChecksNullArenaRef) {
183+
GTEST_SKIP()
184+
<< "Skip until edge case of IsInstanceOf (b/268420201) is covered.";
185+
Local<Class> clazz = env().FindClass("java/lang/String");
186+
ArenaRef arena_ref;
187+
EXPECT_FALSE(env().IsInstanceOf(arena_ref, clazz));
188+
}
189+
163190
TEST_F(EnvTest, Throw) {
164191
Local<Class> clazz = env().FindClass("java/lang/Exception");
165192
jmethodID ctor = env().GetMethodId(clazz, "<init>", "(Ljava/lang/String;)V");

firestore/src/android/document_reference_android.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,14 +147,14 @@ Future<void> DocumentReferenceInternal::Set(const MapFieldValue& data,
147147
Env env = GetEnv();
148148
FieldValueInternal map_value(data);
149149
Local<Object> java_options = SetOptionsInternal::Create(env, options);
150-
Local<Task> task = env.Call(obj_, kSet, map_value, java_options);
150+
Local<Task> task = env.Call(obj_, kSet, map_value.ToJava(), java_options);
151151
return promises_.NewFuture<void>(env, AsyncFn::kSet, task);
152152
}
153153

154154
Future<void> DocumentReferenceInternal::Update(const MapFieldValue& data) {
155155
Env env = GetEnv();
156156
FieldValueInternal map_value(data);
157-
Local<Task> task = env.Call(obj_, kUpdate, map_value);
157+
Local<Task> task = env.Call(obj_, kUpdate, map_value.ToJava());
158158
return promises_.NewFuture<void>(env, AsyncFn::kUpdate, task);
159159
}
160160

0 commit comments

Comments
 (0)