Skip to content

Commit be461e5

Browse files
authored
Add is_valid methods to the public API classes that can be in an invalid state (#560)
Also improve the error message contained in the invalid futures returned from invalid objects. Addresses b/172570071 and b/157227167.
2 parents e945953 + 00c50e4 commit be461e5

File tree

13 files changed

+195
-87
lines changed

13 files changed

+195
-87
lines changed

external/vcpkg

Submodule vcpkg updated 133 files

firestore/integration_test_internal/src/cleanup_test.cc

Lines changed: 87 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ void ExpectAllMethodsAreNoOps(Query* ptr);
1515
// and return null.
1616
template <typename T>
1717
void ExpectNullFirestore(T* ptr) {
18-
EXPECT_TRUE(ptr->firestore() == nullptr);
18+
EXPECT_EQ(ptr->firestore(), nullptr);
1919
// Make sure to check both const and non-const overloads.
20-
EXPECT_TRUE(static_cast<const T*>(ptr)->firestore() == nullptr);
20+
EXPECT_EQ(static_cast<const T*>(ptr)->firestore(), nullptr);
2121
}
2222

2323
// Checks that the given object can be copied from, and the resulting copy can
@@ -48,32 +48,36 @@ void ExpectEqualityToWork(T* ptr) {
4848
// value-initialized values.
4949

5050
void ExpectAllMethodsAreNoOps(CollectionReference* ptr) {
51-
EXPECT_TRUE(*ptr == CollectionReference());
51+
EXPECT_FALSE(ptr->is_valid());
52+
53+
EXPECT_EQ(*ptr, CollectionReference());
5254
ExpectCopyableAndMoveable(ptr);
5355
ExpectEqualityToWork(ptr);
5456

5557
ExpectAllMethodsAreNoOps(static_cast<Query*>(ptr));
5658

57-
EXPECT_TRUE(ptr->id() == "");
58-
EXPECT_TRUE(ptr->path() == "");
59+
EXPECT_EQ(ptr->id(), "");
60+
EXPECT_EQ(ptr->path(), "");
5961

60-
EXPECT_TRUE(ptr->Document() == DocumentReference());
61-
EXPECT_TRUE(ptr->Document("foo") == DocumentReference());
62-
EXPECT_TRUE(ptr->Document(std::string("foo")) == DocumentReference());
62+
EXPECT_EQ(ptr->Document(), DocumentReference());
63+
EXPECT_EQ(ptr->Document("foo"), DocumentReference());
64+
EXPECT_EQ(ptr->Document(std::string("foo")), DocumentReference());
6365

64-
EXPECT_TRUE(ptr->Add(MapFieldValue()) == FailedFuture<DocumentReference>());
66+
EXPECT_EQ(ptr->Add(MapFieldValue()), FailedFuture<DocumentReference>());
6567
}
6668

6769
void ExpectAllMethodsAreNoOps(DocumentChange* ptr) {
70+
EXPECT_FALSE(ptr->is_valid());
71+
6872
// TODO(b/137966104): implement == on `DocumentChange`
6973
// ExpectEqualityToWork(ptr);
7074
ExpectCopyableAndMoveable(ptr);
7175

72-
EXPECT_TRUE(ptr->type() == DocumentChange::Type());
76+
EXPECT_EQ(ptr->type(), DocumentChange::Type());
7377
// TODO(b/137966104): implement == on `DocumentSnapshot`
7478
ptr->document();
75-
EXPECT_TRUE(ptr->old_index() == 0);
76-
EXPECT_TRUE(ptr->new_index() == 0);
79+
EXPECT_EQ(ptr->old_index(), 0);
80+
EXPECT_EQ(ptr->new_index(), 0);
7781
}
7882

7983
void ExpectAllMethodsAreNoOps(DocumentReference* ptr) {
@@ -83,58 +87,61 @@ void ExpectAllMethodsAreNoOps(DocumentReference* ptr) {
8387
ExpectCopyableAndMoveable(ptr);
8488
ExpectNullFirestore(ptr);
8589

86-
EXPECT_TRUE(ptr->ToString() == "DocumentReference(invalid)");
90+
EXPECT_EQ(ptr->ToString(), "DocumentReference(invalid)");
8791

88-
EXPECT_TRUE(ptr->id() == "");
89-
EXPECT_TRUE(ptr->path() == "");
92+
EXPECT_EQ(ptr->id(), "");
93+
EXPECT_EQ(ptr->path(), "");
9094

91-
EXPECT_TRUE(ptr->Parent() == CollectionReference());
92-
EXPECT_TRUE(ptr->Collection("foo") == CollectionReference());
93-
EXPECT_TRUE(ptr->Collection(std::string("foo")) == CollectionReference());
95+
EXPECT_EQ(ptr->Parent(), CollectionReference());
96+
EXPECT_EQ(ptr->Collection("foo"), CollectionReference());
97+
EXPECT_EQ(ptr->Collection(std::string("foo")), CollectionReference());
9498

95-
EXPECT_TRUE(ptr->Get() == FailedFuture<DocumentSnapshot>());
99+
EXPECT_EQ(ptr->Get(), FailedFuture<DocumentSnapshot>());
96100

97-
EXPECT_TRUE(ptr->Set(MapFieldValue()) == FailedFuture<void>());
101+
EXPECT_EQ(ptr->Set(MapFieldValue()), FailedFuture<void>());
98102

99-
EXPECT_TRUE(ptr->Update(MapFieldValue()) == FailedFuture<void>());
100-
EXPECT_TRUE(ptr->Update(MapFieldPathValue()) == FailedFuture<void>());
103+
EXPECT_EQ(ptr->Update(MapFieldValue()), FailedFuture<void>());
104+
EXPECT_EQ(ptr->Update(MapFieldPathValue()), FailedFuture<void>());
101105

102-
EXPECT_TRUE(ptr->Delete() == FailedFuture<void>());
106+
EXPECT_EQ(ptr->Delete(), FailedFuture<void>());
103107

104108
ptr->AddSnapshotListener(
105109
[](const DocumentSnapshot&, Error, const std::string&) {});
106110
}
107111

108112
void ExpectAllMethodsAreNoOps(DocumentSnapshot* ptr) {
113+
EXPECT_FALSE(ptr->is_valid());
114+
109115
// TODO(b/137966104): implement == on `DocumentSnapshot`
110116
// ExpectEqualityToWork(ptr);
111117
ExpectCopyableAndMoveable(ptr);
112118

113-
EXPECT_TRUE(ptr->ToString() == "DocumentSnapshot(invalid)");
119+
EXPECT_EQ(ptr->ToString(), "DocumentSnapshot(invalid)");
114120

115-
EXPECT_TRUE(ptr->id() == "");
121+
EXPECT_EQ(ptr->id(), "");
116122
EXPECT_FALSE(ptr->exists());
117123

118-
EXPECT_TRUE(ptr->reference() == DocumentReference());
124+
EXPECT_EQ(ptr->reference(), DocumentReference());
119125
// TODO(b/137966104): implement == on `SnapshotMetadata`
120126
ptr->metadata();
121127

122-
EXPECT_TRUE(ptr->GetData() == MapFieldValue());
128+
EXPECT_EQ(ptr->GetData(), MapFieldValue());
123129

124-
EXPECT_TRUE(ptr->Get("foo") == FieldValue());
125-
EXPECT_TRUE(ptr->Get(std::string("foo")) == FieldValue());
126-
EXPECT_TRUE(ptr->Get(FieldPath{"foo"}) == FieldValue());
130+
EXPECT_EQ(ptr->Get("foo"), FieldValue());
131+
EXPECT_EQ(ptr->Get(std::string("foo")), FieldValue());
132+
EXPECT_EQ(ptr->Get(FieldPath{"foo"}), FieldValue());
127133
}
128134

129135
void ExpectAllMethodsAreNoOps(FieldValue* ptr) {
136+
EXPECT_FALSE(ptr->is_valid());
137+
130138
ExpectEqualityToWork(ptr);
131139
ExpectCopyableAndMoveable(ptr);
132140

133-
EXPECT_FALSE(ptr->is_valid());
134141
// FieldValue doesn't have a separate "invalid" type in its enum.
135142
EXPECT_TRUE(ptr->is_null());
136143

137-
EXPECT_TRUE(ptr->type() == FieldValue::Type());
144+
EXPECT_EQ(ptr->type(), FieldValue::Type());
138145

139146
EXPECT_FALSE(ptr->is_boolean());
140147
EXPECT_FALSE(ptr->is_integer());
@@ -147,93 +154,100 @@ void ExpectAllMethodsAreNoOps(FieldValue* ptr) {
147154
EXPECT_FALSE(ptr->is_array());
148155
EXPECT_FALSE(ptr->is_map());
149156

150-
EXPECT_TRUE(ptr->boolean_value() == false);
151-
EXPECT_TRUE(ptr->integer_value() == 0);
152-
EXPECT_TRUE(ptr->double_value() == 0);
153-
EXPECT_TRUE(ptr->timestamp_value() == Timestamp());
154-
EXPECT_TRUE(ptr->string_value() == "");
155-
EXPECT_TRUE(ptr->blob_value() == nullptr);
156-
EXPECT_TRUE(ptr->reference_value() == DocumentReference());
157-
EXPECT_TRUE(ptr->geo_point_value() == GeoPoint());
157+
EXPECT_EQ(ptr->boolean_value(), false);
158+
EXPECT_EQ(ptr->integer_value(), 0);
159+
EXPECT_EQ(ptr->double_value(), 0);
160+
EXPECT_EQ(ptr->timestamp_value(), Timestamp());
161+
EXPECT_EQ(ptr->string_value(), "");
162+
EXPECT_EQ(ptr->blob_value(), nullptr);
163+
EXPECT_EQ(ptr->reference_value(), DocumentReference());
164+
EXPECT_EQ(ptr->geo_point_value(), GeoPoint());
158165
EXPECT_TRUE(ptr->array_value().empty());
159166
EXPECT_TRUE(ptr->map_value().empty());
160167
}
161168

162169
void ExpectAllMethodsAreNoOps(ListenerRegistration* ptr) {
170+
EXPECT_FALSE(ptr->is_valid());
171+
163172
// `ListenerRegistration` isn't equality comparable.
164173
ExpectCopyableAndMoveable(ptr);
165174

166175
ptr->Remove();
167176
}
168177

169178
void ExpectAllMethodsAreNoOps(Query* ptr) {
179+
EXPECT_FALSE(ptr->is_valid());
180+
170181
ExpectEqualityToWork(ptr);
171182
ExpectCopyableAndMoveable(ptr);
172183
ExpectNullFirestore(ptr);
173184

174-
EXPECT_TRUE(ptr->WhereEqualTo("foo", FieldValue()) == Query());
175-
EXPECT_TRUE(ptr->WhereEqualTo(FieldPath{"foo"}, FieldValue()) == Query());
185+
EXPECT_EQ(ptr->WhereEqualTo("foo", FieldValue()), Query());
186+
EXPECT_EQ(ptr->WhereEqualTo(FieldPath{"foo"}, FieldValue()), Query());
176187

177-
EXPECT_TRUE(ptr->WhereLessThan("foo", FieldValue()) == Query());
178-
EXPECT_TRUE(ptr->WhereLessThan(FieldPath{"foo"}, FieldValue()) == Query());
188+
EXPECT_EQ(ptr->WhereLessThan("foo", FieldValue()), Query());
189+
EXPECT_EQ(ptr->WhereLessThan(FieldPath{"foo"}, FieldValue()), Query());
179190

180-
EXPECT_TRUE(ptr->WhereLessThanOrEqualTo("foo", FieldValue()) == Query());
181-
EXPECT_TRUE(ptr->WhereLessThanOrEqualTo(FieldPath{"foo"}, FieldValue()) ==
182-
Query());
191+
EXPECT_EQ(ptr->WhereLessThanOrEqualTo("foo", FieldValue()), Query());
192+
EXPECT_EQ(ptr->WhereLessThanOrEqualTo(FieldPath{"foo"}, FieldValue()),
193+
Query());
183194

184-
EXPECT_TRUE(ptr->WhereGreaterThan("foo", FieldValue()) == Query());
185-
EXPECT_TRUE(ptr->WhereGreaterThan(FieldPath{"foo"}, FieldValue()) == Query());
195+
EXPECT_EQ(ptr->WhereGreaterThan("foo", FieldValue()), Query());
196+
EXPECT_EQ(ptr->WhereGreaterThan(FieldPath{"foo"}, FieldValue()), Query());
186197

187-
EXPECT_TRUE(ptr->WhereGreaterThanOrEqualTo("foo", FieldValue()) == Query());
188-
EXPECT_TRUE(ptr->WhereGreaterThanOrEqualTo(FieldPath{"foo"}, FieldValue()) ==
189-
Query());
198+
EXPECT_EQ(ptr->WhereGreaterThanOrEqualTo("foo", FieldValue()), Query());
199+
EXPECT_EQ(ptr->WhereGreaterThanOrEqualTo(FieldPath{"foo"}, FieldValue()),
200+
Query());
190201

191-
EXPECT_TRUE(ptr->WhereArrayContains("foo", FieldValue()) == Query());
192-
EXPECT_TRUE(ptr->WhereArrayContains(FieldPath{"foo"}, FieldValue()) ==
193-
Query());
202+
EXPECT_EQ(ptr->WhereArrayContains("foo", FieldValue()), Query());
203+
EXPECT_EQ(ptr->WhereArrayContains(FieldPath{"foo"}, FieldValue()), Query());
194204

195-
EXPECT_TRUE(ptr->OrderBy("foo") == Query());
196-
EXPECT_TRUE(ptr->OrderBy(FieldPath{"foo"}) == Query());
205+
EXPECT_EQ(ptr->OrderBy("foo"), Query());
206+
EXPECT_EQ(ptr->OrderBy(FieldPath{"foo"}), Query());
197207

198-
EXPECT_TRUE(ptr->Limit(123) == Query());
208+
EXPECT_EQ(ptr->Limit(123), Query());
199209

200-
EXPECT_TRUE(ptr->StartAt(DocumentSnapshot()) == Query());
201-
EXPECT_TRUE(ptr->StartAt(std::vector<FieldValue>()) == Query());
210+
EXPECT_EQ(ptr->StartAt(DocumentSnapshot()), Query());
211+
EXPECT_EQ(ptr->StartAt(std::vector<FieldValue>()), Query());
202212

203-
EXPECT_TRUE(ptr->StartAfter(DocumentSnapshot()) == Query());
204-
EXPECT_TRUE(ptr->StartAfter(std::vector<FieldValue>()) == Query());
213+
EXPECT_EQ(ptr->StartAfter(DocumentSnapshot()), Query());
214+
EXPECT_EQ(ptr->StartAfter(std::vector<FieldValue>()), Query());
205215

206-
EXPECT_TRUE(ptr->EndBefore(DocumentSnapshot()) == Query());
207-
EXPECT_TRUE(ptr->EndBefore(std::vector<FieldValue>()) == Query());
216+
EXPECT_EQ(ptr->EndBefore(DocumentSnapshot()), Query());
217+
EXPECT_EQ(ptr->EndBefore(std::vector<FieldValue>()), Query());
208218

209-
EXPECT_TRUE(ptr->EndAt(DocumentSnapshot()) == Query());
210-
EXPECT_TRUE(ptr->EndAt(std::vector<FieldValue>()) == Query());
219+
EXPECT_EQ(ptr->EndAt(DocumentSnapshot()), Query());
220+
EXPECT_EQ(ptr->EndAt(std::vector<FieldValue>()), Query());
211221

212-
EXPECT_TRUE(ptr->Get() == FailedFuture<QuerySnapshot>());
222+
EXPECT_EQ(ptr->Get(), FailedFuture<QuerySnapshot>());
213223

214-
EXPECT_TRUE(ptr->Get() == FailedFuture<QuerySnapshot>());
224+
EXPECT_EQ(ptr->Get(), FailedFuture<QuerySnapshot>());
215225

216226
ptr->AddSnapshotListener(
217227
[](const QuerySnapshot&, Error, const std::string&) {});
218228
}
219229

220230
void ExpectAllMethodsAreNoOps(QuerySnapshot* ptr) {
231+
EXPECT_FALSE(ptr->is_valid());
232+
221233
// TODO(b/137966104): implement == on `QuerySnapshot`
222234
// ExpectEqualityToWork(ptr);
223235
ExpectCopyableAndMoveable(ptr);
224236

225-
EXPECT_TRUE(ptr->query() == Query());
237+
EXPECT_EQ(ptr->query(), Query());
226238

227239
// TODO(b/137966104): implement == on `SnapshotMetadata`
228240
ptr->metadata();
229241

230242
EXPECT_TRUE(ptr->DocumentChanges().empty());
231243
EXPECT_TRUE(ptr->documents().empty());
232244
EXPECT_TRUE(ptr->empty());
233-
EXPECT_TRUE(ptr->size() == 0);
245+
EXPECT_EQ(ptr->size(), 0);
234246
}
235247

236248
void ExpectAllMethodsAreNoOps(WriteBatch* ptr) {
249+
EXPECT_FALSE(ptr->is_valid());
250+
237251
// `WriteBatch` isn't equality comparable.
238252
ExpectCopyableAndMoveable(ptr);
239253

@@ -244,7 +258,7 @@ void ExpectAllMethodsAreNoOps(WriteBatch* ptr) {
244258

245259
ptr->Delete(DocumentReference());
246260

247-
EXPECT_TRUE(ptr->Commit() == FailedFuture<void>());
261+
EXPECT_EQ(ptr->Commit(), FailedFuture<void>());
248262
}
249263

250264
using CleanupTest = FirestoreIntegrationTest;
@@ -337,7 +351,7 @@ TEST_F(CleanupTest, FieldValueIsBlankAfterCleanup) {
337351
// stay valid after Firestore has shut down.
338352
EXPECT_TRUE(str_value.is_valid());
339353
EXPECT_TRUE(str_value.is_string());
340-
EXPECT_TRUE(str_value.string_value() == "bar");
354+
EXPECT_EQ(str_value.string_value(), "bar");
341355

342356
// However, need to make sure that in a reference value, the reference was
343357
// cleaned up.
@@ -382,7 +396,7 @@ TEST_F(CleanupTest, QuerySnapshotIsBlankAfterCleanup) {
382396
WriteDocument(doc, MapFieldValue{{"foo", FieldValue::String("bar")}});
383397

384398
QuerySnapshot snap = ReadDocuments(col);
385-
EXPECT_TRUE(snap.size() == 1);
399+
EXPECT_EQ(snap.size(), 1);
386400

387401
DeleteFirestore(col.firestore());
388402
SCOPED_TRACE("QuerySnapshot.AfterCleanup");

firestore/src/common/futures.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ template <typename T>
5555
Future<T> FailedFuture() {
5656
static auto* future = new Future<T>(FailedFuture<T>(
5757
Error::kErrorFailedPrecondition,
58-
"This instance is in an invalid state. This is because the underlying "
59-
"Firestore instance has been destructed."));
58+
"The object that issued this future is in an invalid state. This can be "
59+
"because the object was default-constructed and never reassigned, "
60+
"the object was moved from, or the Firestore instance with which the "
61+
"object was associated has been destroyed."));
6062
return *future;
6163
}
6264

firestore/src/include/firebase/firestore/document_change.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,19 @@ class DocumentChange {
159159
*/
160160
virtual std::size_t new_index() const;
161161

162+
/**
163+
* @brief Returns true if this `DocumentChange` is valid, false if it is
164+
* not valid. An invalid `DocumentChange` could be the result of:
165+
* - Creating a `DocumentChange` using the default constructor.
166+
* - Moving from the `DocumentChange`.
167+
* - Deleting your Firestore instance, which will invalidate all the
168+
* `DocumentChange` instances associated with it.
169+
*
170+
* @return true if this `DocumentChange` is valid, false if this
171+
* `DocumentChange` is invalid.
172+
*/
173+
bool is_valid() const { return internal_ != nullptr; }
174+
162175
private:
163176
friend class FirestoreInternal;
164177
friend class Wrapper;

firestore/src/include/firebase/firestore/document_reference.h

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -285,16 +285,17 @@ class DocumentReference {
285285
callback);
286286

287287
/**
288-
* @brief Returns true if this DocumentReference is valid, false if it is not
289-
* valid. An invalid DocumentReference could be the result of:
290-
* - Creating a DocumentReference with the default constructor.
291-
* - Calling CollectionReference::Parent() on a CollectionReference that is
292-
* not a subcollection.
293-
* - Deleting your Firestore instance, which will invalidate all
294-
* DocumentReference instances associated with it.
295-
*
296-
* @return true if this DocumentReference is valid, false if this
297-
* DocumentReference is invalid.
288+
* @brief Returns true if this `DocumentReference` is valid, false if it is
289+
* not valid. An invalid `DocumentReference` could be the result of:
290+
* - Creating a `DocumentReference` using the default constructor.
291+
* - Moving from the `DocumentReference`.
292+
* - Calling `CollectionReference::Parent()` on a `CollectionReference` that
293+
* is not a subcollection.
294+
* - Deleting your Firestore instance, which will invalidate all the
295+
* `DocumentReference` instances associated with it.
296+
*
297+
* @return true if this `DocumentReference` is valid, false if this
298+
* `DocumentReference` is invalid.
298299
*/
299300
bool is_valid() const { return internal_ != nullptr; }
300301

firestore/src/include/firebase/firestore/document_snapshot.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,19 @@ class DocumentSnapshot {
229229
const FieldPath& field,
230230
ServerTimestampBehavior stb = ServerTimestampBehavior::kDefault) const;
231231

232+
/**
233+
* @brief Returns true if this `DocumentSnapshot` is valid, false if it is
234+
* not valid. An invalid `DocumentSnapshot` could be the result of:
235+
* - Creating a `DocumentSnapshot` with the default constructor.
236+
* - Moving from the `DocumentSnapshot`.
237+
* - Deleting your Firestore instance, which will invalidate all the
238+
* `DocumentSnapshot` instances associated with it.
239+
*
240+
* @return true if this `DocumentSnapshot` is valid, false if this
241+
* `DocumentSnapshot` is invalid.
242+
*/
243+
bool is_valid() const { return internal_ != nullptr; }
244+
232245
/**
233246
* Returns a string representation of this `DocumentSnapshot` for
234247
* logging/debugging purposes.

0 commit comments

Comments
 (0)