Skip to content

Commit b63708a

Browse files
authored
firestore_integration_test_android.h: add ThrowException/CreateException functions (#1346)
1 parent cc89a20 commit b63708a

File tree

5 files changed

+174
-16
lines changed

5 files changed

+174
-16
lines changed

firestore/integration_test_internal/src/android/firestore_integration_test_android.cc

+49-5
Original file line numberDiff line numberDiff line change
@@ -70,22 +70,66 @@ void FirestoreAndroidIntegrationTest::SetUp() {
7070
void FirestoreAndroidIntegrationTest::TearDown() {
7171
// Fail the test if there is a pending Java exception. Clear the pending
7272
// exception as well so that it doesn't bleed into the next test.
73+
FailTestIfPendingException();
74+
75+
// Perform the tear-down steps of the superclass.
76+
FirestoreIntegrationTest::TearDown();
77+
}
78+
79+
void FirestoreAndroidIntegrationTest::FailTestIfPendingException() {
7380
Env env;
7481
Local<Throwable> pending_exception = env.ClearExceptionOccurred();
75-
EXPECT_FALSE(pending_exception)
76-
<< "Test completed with a pending Java exception: "
77-
<< pending_exception.ToString(env);
82+
if (!pending_exception) {
83+
return;
84+
}
85+
86+
// Ignore the exception if it was thrown by the last ThrowException() call.
87+
if (env.IsSameObject(pending_exception, last_thrown_exception_)) {
88+
return;
89+
}
90+
91+
// Fail the test since the test completed with a pending exception.
92+
std::string pending_exception_as_string = pending_exception.ToString(env);
7893
env.ExceptionClear();
79-
FirestoreIntegrationTest::TearDown();
94+
FAIL() << "Test completed with a pending Java exception: "
95+
<< pending_exception_as_string;
96+
}
97+
98+
Local<Throwable> FirestoreAndroidIntegrationTest::CreateException(Env& env) {
99+
return CreateException(env,
100+
"Test exception created by "
101+
"FirestoreAndroidIntegrationTest::CreateException()");
80102
}
81103

82104
Local<Throwable> FirestoreAndroidIntegrationTest::CreateException(
83105
Env& env, const std::string& message) {
84-
ExceptionClearGuard block(env);
106+
ExceptionClearGuard exception_clear_guard(env);
85107
Local<String> java_message = env.NewStringUtf(message);
86108
return env.New(kExceptionConstructor, java_message);
87109
}
88110

111+
Local<Throwable> FirestoreAndroidIntegrationTest::ThrowException(Env& env) {
112+
return ThrowException(env,
113+
"Test exception thrown by "
114+
"FirestoreAndroidIntegrationTest::ThrowException()");
115+
}
116+
117+
Local<Throwable> FirestoreAndroidIntegrationTest::ThrowException(
118+
Env& env, const std::string& message) {
119+
if (!env.ok()) {
120+
ADD_FAILURE() << "ThrowException() invoked while there is already a "
121+
"pending exception";
122+
return {};
123+
}
124+
Local<Throwable> exception = CreateException(env, message);
125+
126+
// Silently discard this exception if the test ends with it still pending.
127+
last_thrown_exception_ = exception;
128+
129+
env.Throw(exception);
130+
return exception;
131+
}
132+
89133
void FirestoreAndroidIntegrationTest::Await(Env& env, const Task& task) {
90134
int cycles = kTimeOutMillis / kCheckIntervalMillis;
91135
while (env.ok() && !task.IsComplete(env)) {

firestore/integration_test_internal/src/android/firestore_integration_test_android.h

+34-3
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,26 @@ MATCHER_P(JavaEq,
7474
return jni::Object::Equals(env, object, arg);
7575
}
7676

77+
/**
78+
* A gmock matcher that compares two Java objects for equality using the ==
79+
* operator; that is, that they both refer to the _same_ Java object.
80+
*
81+
* Example:
82+
*
83+
* jni::Env env;
84+
* jni::Local<jni::String> object1 = env.NewStringUtf("string");
85+
* jni::Local<jni::String> object2 = object1;
86+
* EXPECT_THAT(object1, RefersToSameJavaObjectAs(object2));
87+
*/
88+
MATCHER_P(RefersToSameJavaObjectAs,
89+
object,
90+
std::string("is ") + (negation ? "not " : "") +
91+
" referring to the same object as " + ToDebugString(object)) {
92+
jni::Env env;
93+
jni::ExceptionClearGuard block(env);
94+
return env.IsSameObject(arg, object);
95+
}
96+
7797
/** Adds Android-specific functionality to `FirestoreIntegrationTest`. */
7898
class FirestoreAndroidIntegrationTest : public FirestoreIntegrationTest {
7999
public:
@@ -85,9 +105,17 @@ class FirestoreAndroidIntegrationTest : public FirestoreIntegrationTest {
85105

86106
jni::Loader& loader() { return loader_; }
87107

88-
/** Creates and returns a new Java `Exception` object with a message. */
89-
jni::Local<jni::Throwable> CreateException(jni::Env& env,
90-
const std::string& message);
108+
/** Creates and returns a new Java `Exception` with a default message. */
109+
static jni::Local<jni::Throwable> CreateException(jni::Env&);
110+
/** Creates and returns a new Java `Exception` with the given message. */
111+
static jni::Local<jni::Throwable> CreateException(jni::Env&,
112+
const std::string& message);
113+
114+
/** Throws a Java `Exception` object with a default message. */
115+
jni::Local<jni::Throwable> ThrowException(jni::Env&);
116+
/** Throws a Java `Exception` object with the given message. */
117+
jni::Local<jni::Throwable> ThrowException(jni::Env&,
118+
const std::string& message);
91119

92120
// Bring definitions of `Await()` from the superclass into this class so that
93121
// the definition below *overloads* instead of *hides* them.
@@ -97,7 +125,10 @@ class FirestoreAndroidIntegrationTest : public FirestoreIntegrationTest {
97125
static void Await(jni::Env& env, const jni::Task& task);
98126

99127
private:
128+
void FailTestIfPendingException();
129+
100130
jni::Loader loader_;
131+
jni::Global<jni::Throwable> last_thrown_exception_;
101132
};
102133

103134
} // namespace firestore

firestore/integration_test_internal/src/android/firestore_integration_test_android_test.cc

+85-2
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,15 @@ namespace {
3131

3232
using jni::ArrayList;
3333
using jni::Env;
34+
using jni::Global;
3435
using jni::Local;
3536
using jni::Object;
3637
using jni::String;
38+
using jni::Throwable;
3739

40+
using ::testing::IsEmpty;
3841
using ::testing::Not;
42+
using ::testing::StrEq;
3943

4044
TEST_F(FirestoreAndroidIntegrationTest, ToDebugStringWithNonNull) {
4145
Env env;
@@ -57,7 +61,7 @@ TEST_F(FirestoreAndroidIntegrationTest,
5761
ToDebugStringWithPendingExceptionAndNonNullObject) {
5862
Env env;
5963
Local<String> object = env.NewStringUtf("Test Value");
60-
env.Throw(CreateException(env, "forced exception"));
64+
ThrowException(env);
6165
ASSERT_FALSE(env.ok());
6266

6367
std::string debug_string = ToDebugString(object);
@@ -70,7 +74,7 @@ TEST_F(FirestoreAndroidIntegrationTest,
7074
ToDebugStringWithPendingExceptionAndNullObject) {
7175
Env env;
7276
Object null_reference;
73-
env.Throw(CreateException(env, "forced exception"));
77+
ThrowException(env);
7478
ASSERT_FALSE(env.ok());
7579

7680
std::string debug_string = ToDebugString(null_reference);
@@ -125,6 +129,85 @@ TEST_F(FirestoreAndroidIntegrationTest,
125129
EXPECT_THAT(list_object, Not(JavaEq(string_object)));
126130
}
127131

132+
TEST_F(FirestoreAndroidIntegrationTest,
133+
RefersToSameJavaObjectAsShouldReturnTrueForSameObjects) {
134+
Env env;
135+
Local<String> object1 = env.NewStringUtf("string");
136+
Global<String> object2 = object1;
137+
138+
EXPECT_THAT(object1, RefersToSameJavaObjectAs(object2));
139+
}
140+
141+
TEST_F(FirestoreAndroidIntegrationTest,
142+
RefersToSameJavaObjectAsShouldReturnTrueForTwoNullReferences) {
143+
Local<Object> null_reference1;
144+
Local<Object> null_reference2;
145+
146+
EXPECT_THAT(null_reference1, RefersToSameJavaObjectAs(null_reference2));
147+
}
148+
149+
TEST_F(FirestoreAndroidIntegrationTest,
150+
RefersToSameJavaObjectAsShouldReturnFalseForDistinctObjects) {
151+
Env env;
152+
Local<String> object1 = env.NewStringUtf("test string");
153+
Local<String> object2 = env.NewStringUtf("test string");
154+
ASSERT_FALSE(env.IsSameObject(object1, object2));
155+
156+
EXPECT_THAT(object1, Not(RefersToSameJavaObjectAs(object2)));
157+
}
158+
159+
TEST_F(FirestoreAndroidIntegrationTest,
160+
RefersToSameJavaObjectAsShouldReturnFalseIfExactlyOneObjectIsNull) {
161+
Env env;
162+
Local<String> null_reference;
163+
Local<String> non_null_reference = env.NewStringUtf("string2");
164+
165+
EXPECT_THAT(null_reference,
166+
Not(RefersToSameJavaObjectAs(non_null_reference)));
167+
EXPECT_THAT(non_null_reference,
168+
Not(RefersToSameJavaObjectAs(null_reference)));
169+
}
170+
171+
TEST_F(FirestoreAndroidIntegrationTest,
172+
ThrowExceptionWithNoMessageShouldSetPendingExceptionWithAMessage) {
173+
Env env;
174+
Local<Throwable> throw_exception_return_value = ThrowException(env);
175+
Local<Throwable> actually_thrown_exception = env.ClearExceptionOccurred();
176+
ASSERT_TRUE(actually_thrown_exception);
177+
EXPECT_THAT(actually_thrown_exception,
178+
RefersToSameJavaObjectAs(throw_exception_return_value));
179+
EXPECT_THAT(actually_thrown_exception.GetMessage(env), Not(IsEmpty()));
180+
}
181+
182+
TEST_F(FirestoreAndroidIntegrationTest,
183+
ThrowExceptionWithAMessageShouldSetPendingExceptionWithTheGivenMessage) {
184+
Env env;
185+
Local<Throwable> throw_exception_return_value =
186+
ThrowException(env, "my test message");
187+
Local<Throwable> actually_thrown_exception = env.ClearExceptionOccurred();
188+
ASSERT_TRUE(actually_thrown_exception);
189+
EXPECT_THAT(actually_thrown_exception,
190+
RefersToSameJavaObjectAs(throw_exception_return_value));
191+
EXPECT_THAT(actually_thrown_exception.GetMessage(env),
192+
StrEq("my test message"));
193+
}
194+
195+
TEST_F(FirestoreAndroidIntegrationTest,
196+
CreateExceptionWithNoMessageShouldReturnAnExceptionWithAMessage) {
197+
Env env;
198+
Local<Throwable> exception = CreateException(env);
199+
ASSERT_TRUE(exception);
200+
EXPECT_THAT(exception.GetMessage(env), Not(IsEmpty()));
201+
}
202+
203+
TEST_F(FirestoreAndroidIntegrationTest,
204+
CreateExceptionWithAMessageShouldReturnAnExceptionWithTheGivenMessage) {
205+
Env env;
206+
Local<Throwable> exception = CreateException(env, "my test message");
207+
ASSERT_TRUE(exception);
208+
EXPECT_THAT(exception.GetMessage(env), StrEq("my test message"));
209+
}
210+
128211
} // namespace
129212
} // namespace firestore
130213
} // namespace firebase

firestore/integration_test_internal/src/android/jni_runnable_android_test.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ TEST_F(JniRunnableTest, JavaRunCallsCppRunOncePerInvocation) {
119119

120120
TEST_F(JniRunnableTest, JavaRunPropagatesExceptions) {
121121
Env env;
122-
Local<Throwable> exception = CreateException(env, "Forced exception");
122+
Local<Throwable> exception = CreateException(env);
123123
auto runnable = MakeJniRunnable(env, [exception] {
124124
Env env;
125125
env.Throw(exception);
@@ -166,7 +166,7 @@ TEST_F(JniRunnableTest, DetachDetachesEvenIfAnExceptionIsPending) {
166166
bool invoked = false;
167167
auto runnable = MakeJniRunnable(env, [&invoked] { invoked = true; });
168168
Local<Object> java_runnable = runnable.GetJavaRunnable();
169-
Local<Throwable> exception = CreateException(env, "Forced exception");
169+
Local<Throwable> exception = CreateException(env);
170170
env.Throw(exception);
171171
EXPECT_FALSE(env.ok());
172172

@@ -230,7 +230,7 @@ TEST_F(JniRunnableTest, RunOnMainThreadRunsOnTheMainThread) {
230230

231231
TEST_F(JniRunnableTest, RunOnMainThreadTaskFailsIfRunThrowsException) {
232232
Env env;
233-
Global<Throwable> exception = CreateException(env, "Forced exception");
233+
Global<Throwable> exception = CreateException(env);
234234
auto runnable = MakeJniRunnable(env, [exception] {
235235
Env env;
236236
env.Throw(exception);
@@ -284,7 +284,7 @@ TEST_F(JniRunnableTest, RunOnNewThreadRunsOnANonMainThread) {
284284

285285
TEST_F(JniRunnableTest, RunOnNewThreadTaskFailsIfRunThrowsException) {
286286
Env env;
287-
Global<Throwable> exception = CreateException(env, "Forced exception");
287+
Global<Throwable> exception = CreateException(env);
288288
auto runnable = MakeJniRunnable(env, [exception] {
289289
Env env;
290290
env.Throw(exception);

firestore/integration_test_internal/src/jni/task_test.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class TaskTest : public FirestoreAndroidIntegrationTest {
5858
}
5959

6060
Local<Task> CreateFailedTask(Env& env) {
61-
auto exception = CreateException(env, "Test Exception");
61+
auto exception = CreateException(env);
6262
return CreateFailedTask(env, exception);
6363
}
6464

@@ -86,7 +86,7 @@ TEST_F(TaskTest, GetResultShouldReturnTheResult) {
8686

8787
TEST_F(TaskTest, GetExceptionShouldReturnTheException) {
8888
Env env;
89-
Local<Throwable> exception = CreateException(env, "Test Exception");
89+
Local<Throwable> exception = CreateException(env);
9090
Local<Task> task = CreateFailedTask(env, exception);
9191

9292
Local<Throwable> actual_exception = task.GetException(env);

0 commit comments

Comments
 (0)