Skip to content

Commit 60eb272

Browse files
committed
Fixes
1 parent 77dfc07 commit 60eb272

File tree

5 files changed

+48
-63
lines changed

5 files changed

+48
-63
lines changed

firebase-firestore/src/roboUtil/java/com/google/firebase/firestore/TestUtil.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@
4040

4141
public class TestUtil {
4242

43-
private static final FirebaseFirestore FIRESTORE = mock(FirebaseFirestore.class);
43+
public static final FirebaseFirestore FIRESTORE = mock(FirebaseFirestore.class);
4444
private static final DatabaseId DATABASE_ID = DatabaseId.forProject("project");
45-
private static final UserDataReader USER_DATA_READER = new UserDataReader(DATABASE_ID);
45+
public static final UserDataReader USER_DATA_READER = new UserDataReader(DATABASE_ID);
4646

4747
static {
4848
when(FIRESTORE.getDatabaseId()).thenReturn(DATABASE_ID);

firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/SortTests.kt

Lines changed: 41 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package com.google.firebase.firestore.pipeline
1616

1717
import com.google.common.truth.Truth.assertThat
18+
import com.google.firebase.firestore.FieldPath as PublicFieldPath
1819
import com.google.firebase.firestore.RealtimePipelineSource
1920
import com.google.firebase.firestore.TestUtil
2021
import com.google.firebase.firestore.model.MutableDocument
@@ -31,7 +32,6 @@ import kotlinx.coroutines.runBlocking
3132
import org.junit.Test
3233
import org.junit.runner.RunWith
3334
import org.robolectric.RobolectricTestRunner
34-
import com.google.firebase.firestore.FieldPath as PublicFieldPath
3535

3636
@RunWith(RobolectricTestRunner::class)
3737
internal class SortTests {
@@ -41,10 +41,7 @@ internal class SortTests {
4141
@Test
4242
fun `empty ascending`(): Unit = runBlocking {
4343
val documents = emptyList<MutableDocument>()
44-
val pipeline =
45-
RealtimePipelineSource(db)
46-
.collection("users")
47-
.sort(field("age").ascending())
44+
val pipeline = RealtimePipelineSource(db).collection("users").sort(field("age").ascending())
4845

4946
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
5047
assertThat(result).isEmpty()
@@ -53,10 +50,7 @@ internal class SortTests {
5350
@Test
5451
fun `empty descending`(): Unit = runBlocking {
5552
val documents = emptyList<MutableDocument>()
56-
val pipeline =
57-
RealtimePipelineSource(db)
58-
.collection("users")
59-
.sort(field("age").descending())
53+
val pipeline = RealtimePipelineSource(db).collection("users").sort(field("age").descending())
6054

6155
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
6256
assertThat(result).isEmpty()
@@ -66,10 +60,7 @@ internal class SortTests {
6660
fun `single result ascending`(): Unit = runBlocking {
6761
val doc1 = doc("users/a", 1000, mapOf("name" to "alice", "age" to 10L))
6862
val documents = listOf(doc1)
69-
val pipeline =
70-
RealtimePipelineSource(db)
71-
.collection("users")
72-
.sort(field("age").ascending())
63+
val pipeline = RealtimePipelineSource(db).collection("users").sort(field("age").ascending())
7364

7465
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
7566
assertThat(result).containsExactly(doc1)
@@ -121,10 +112,7 @@ internal class SortTests {
121112
fun `single result descending`(): Unit = runBlocking {
122113
val doc1 = doc("users/a", 1000, mapOf("name" to "alice", "age" to 10L))
123114
val documents = listOf(doc1)
124-
val pipeline =
125-
RealtimePipelineSource(db)
126-
.collection("users")
127-
.sort(field("age").descending())
115+
val pipeline = RealtimePipelineSource(db).collection("users").sort(field("age").descending())
128116

129117
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
130118
assertThat(result).containsExactly(doc1)
@@ -167,24 +155,25 @@ internal class SortTests {
167155
val doc5 = doc("users/e", 1000, mapOf("name" to "eric", "age" to 10.0))
168156
val documents = listOf(doc1, doc2, doc3, doc4, doc5)
169157

170-
val pipeline =
171-
RealtimePipelineSource(db)
172-
.collection("users")
173-
.sort(field("age").descending())
158+
val pipeline = RealtimePipelineSource(db).collection("users").sort(field("age").descending())
174159

175160
// Order: doc3 (100.0), doc1 (75.5), doc2 (25.0), then doc4 and doc5 (10.0) are ambiguous
176161
// Firestore backend sorts by document key as a tie-breaker.
177-
// So expected order: doc3, doc1, doc2, doc4, doc5 (if 'd' < 'e') or doc3, doc1, doc2, doc5, doc4 (if 'e' < 'd')
162+
// So expected order: doc3, doc1, doc2, doc4, doc5 (if 'd' < 'e') or doc3, doc1, doc2, doc5,
163+
// doc4 (if 'e' < 'd')
178164
// Since the C++ test uses UnorderedElementsAre, we'll use containsExactlyElementsIn.
179165
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
180166
assertThat(result).containsExactlyElementsIn(listOf(doc3, doc1, doc2, doc4, doc5)).inOrder()
181-
// Actually, the local pipeline implementation might not guarantee tie-breaking by key unless explicitly added.
182-
// The C++ test uses UnorderedElementsAre, which means the exact order of doc4 and doc5 is not tested.
183-
// Let's stick to what the C++ test implies: the overall set is correct, but the order of tied elements is not strictly defined by this single sort.
167+
// Actually, the local pipeline implementation might not guarantee tie-breaking by key unless
168+
// explicitly added.
169+
// The C++ test uses UnorderedElementsAre, which means the exact order of doc4 and doc5 is not
170+
// tested.
171+
// Let's stick to what the C++ test implies: the overall set is correct, but the order of tied
172+
// elements is not strictly defined by this single sort.
184173
// However, the local pipeline *does* sort by key as a final tie-breaker.
185174
// Expected: doc3 (100.0), doc1 (75.5), doc2 (25.0), doc4 (10.0, key d), doc5 (10.0, key e)
186175
// So the order should be doc3, doc1, doc2, doc4, doc5
187-
assertThat(result).containsExactly(doc3, doc1, doc2, doc4, doc5).inOrder()
176+
assertThat(result).containsExactly(doc3, doc1, doc2, doc4, doc5).inOrder()
188177
}
189178

190179
@Test
@@ -271,7 +260,7 @@ internal class SortTests {
271260
val doc2 = doc("users/b", 1000, mapOf("name" to "bob"))
272261
val doc3 = doc("users/c", 1000, mapOf("age" to 100.0))
273262
val doc4 = doc("users/d", 1000, mapOf("other_name" to "diane")) // Matches
274-
val doc5 = doc("users/e", 1000, mapOf("other_age" to 10.0)) // Matches
263+
val doc5 = doc("users/e", 1000, mapOf("other_age" to 10.0)) // Matches
275264
val documents = listOf(doc1, doc2, doc3, doc4, doc5)
276265

277266
val pipeline =
@@ -332,7 +321,7 @@ internal class SortTests {
332321
val doc2 = doc("users/b", 1000, mapOf("age" to 25.0)) // name missing -> Match
333322
val doc3 = doc("users/c", 1000, mapOf("name" to "charlie", "age" to 100.0))
334323
val doc4 = doc("users/d", 1000, mapOf("name" to "diane")) // age missing, name exists
335-
val doc5 = doc("users/e", 1000, mapOf("name" to "eric")) // age missing, name exists
324+
val doc5 = doc("users/e", 1000, mapOf("name" to "eric")) // age missing, name exists
336325
val documents = listOf(doc1, doc2, doc3, doc4, doc5)
337326

338327
val pipeline =
@@ -345,13 +334,14 @@ internal class SortTests {
345334
assertThat(result).containsExactly(doc2)
346335
}
347336

348-
@Test
349-
fun `multiple results full order partial explicit not exists sort on non exist field first`(): Unit = runBlocking {
337+
@Test
338+
fun `multiple results full order partial explicit not exists sort on non exist field first`():
339+
Unit = runBlocking {
350340
val doc1 = doc("users/a", 1000, mapOf("name" to "alice", "age" to 75.5))
351341
val doc2 = doc("users/b", 1000, mapOf("age" to 25.0)) // name missing -> Match
352342
val doc3 = doc("users/c", 1000, mapOf("name" to "charlie", "age" to 100.0))
353343
val doc4 = doc("users/d", 1000, mapOf("name" to "diane")) // age missing, name exists
354-
val doc5 = doc("users/e", 1000, mapOf("name" to "eric")) // age missing, name exists
344+
val doc5 = doc("users/e", 1000, mapOf("name" to "eric")) // age missing, name exists
355345
val documents = listOf(doc1, doc2, doc3, doc4, doc5)
356346

357347
val pipeline =
@@ -393,9 +383,7 @@ internal class SortTests {
393383
val documents = listOf(doc1, doc2, doc3, doc4, doc5)
394384

395385
val pipeline =
396-
RealtimePipelineSource(db)
397-
.collection("users")
398-
.sort(field("not_age").descending())
386+
RealtimePipelineSource(db).collection("users").sort(field("not_age").descending())
399387

400388
// Sorting by a missing field results in undefined order relative to each other,
401389
// but documents are secondarily sorted by key.
@@ -427,10 +415,7 @@ internal class SortTests {
427415
val doc5 = doc("users/e", 1000, mapOf("name" to "eric", "age" to 10.0))
428416
val documents = listOf(doc1, doc2, doc3, doc4, doc5)
429417

430-
val pipeline =
431-
RealtimePipelineSource(db)
432-
.collection("users")
433-
.sort(field("age").ascending())
418+
val pipeline = RealtimePipelineSource(db).collection("users").sort(field("age").ascending())
434419

435420
// Missing fields sort first in ascending order, then by key. b < d
436421
// Then existing fields sorted by value: e (10.0) < a (75.5) < c (100.0)
@@ -525,7 +510,7 @@ internal class SortTests {
525510
val doc2 = doc("users/b", 1000, mapOf("age" to 25.0)) // name missing
526511
val doc3 = doc("users/c", 1000, mapOf("name" to "charlie", "age" to 100.0))
527512
val doc4 = doc("users/d", 1000, mapOf("name" to "diane")) // age missing -> Match
528-
val doc5 = doc("users/e", 1000, mapOf("name" to "eric")) // age missing -> Match
513+
val doc5 = doc("users/e", 1000, mapOf("name" to "eric")) // age missing -> Match
529514
val documents = listOf(doc1, doc2, doc3, doc4, doc5)
530515

531516
val pipeline =
@@ -544,10 +529,7 @@ internal class SortTests {
544529
val doc1 = doc("users/a", 1000, mapOf("name" to "alice", "age" to 75.5))
545530
val documents = listOf(doc1)
546531
val pipeline =
547-
RealtimePipelineSource(db)
548-
.collection("users")
549-
.sort(field("age").ascending())
550-
.limit(0)
532+
RealtimePipelineSource(db).collection("users").sort(field("age").ascending()).limit(0)
551533

552534
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
553535
assertThat(result).isEmpty()
@@ -599,7 +581,7 @@ internal class SortTests {
599581
val doc2 = doc("users/b", 1000, mapOf("age" to 25.0))
600582
val doc3 = doc("users/c", 1000, mapOf("name" to "charlie", "age" to 100.0))
601583
val doc4 = doc("users/d", 1000, mapOf("name" to "diane")) // Match
602-
val doc5 = doc("users/e", 1000, mapOf("name" to "eric")) // Match
584+
val doc5 = doc("users/e", 1000, mapOf("name" to "eric")) // Match
603585
val documents = listOf(doc1, doc2, doc3, doc4, doc5)
604586

605587
val pipeline =
@@ -638,10 +620,7 @@ internal class SortTests {
638620
val doc1 = doc("users/a", 1000, mapOf("name" to "alice", "age" to 75.5))
639621
val documents = listOf(doc1)
640622
val pipeline =
641-
RealtimePipelineSource(db)
642-
.collectionGroup("users")
643-
.limit(0)
644-
.sort(field("age").ascending())
623+
RealtimePipelineSource(db).collectionGroup("users").limit(0).sort(field("age").ascending())
645624

646625
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
647626
assertThat(result).isEmpty()
@@ -704,7 +683,7 @@ internal class SortTests {
704683
val doc2 = doc("users/b", 1000, mapOf("age" to 30L))
705684
val doc3 = doc("users/c", 1000, mapOf("name" to "charlie", "age" to 50L))
706685
val doc4 = doc("users/d", 1000, mapOf("name" to "diane")) // age missing -> Match
707-
val doc5 = doc("users/e", 1000, mapOf("name" to "eric")) // age missing -> Match
686+
val doc5 = doc("users/e", 1000, mapOf("name" to "eric")) // age missing -> Match
708687
val documents = listOf(doc1, doc2, doc3, doc4, doc5)
709688

710689
val pipeline =
@@ -714,7 +693,8 @@ internal class SortTests {
714693
.sort(add(field("age"), constant(10L)).descending()) // Sort by missing field -> key order
715694

716695
// Filtered: doc4, doc5
717-
// Sort by (age+10) desc where age is missing. This means they are treated as null for the expression.
696+
// Sort by (age+10) desc where age is missing. This means they are treated as null for the
697+
// expression.
718698
// Then tie-broken by key: d, e
719699
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
720700
assertThat(result).containsExactly(doc4, doc5).inOrder()
@@ -732,11 +712,15 @@ internal class SortTests {
732712
.collection("users")
733713
.where(exists(field(PublicFieldPath.documentId()))) // Ensure __name__ is considered
734714
.sort(field(PublicFieldPath.documentId()).ascending()) // Sort by key: 1, 2, 3
735-
.sort(field("age").ascending()) // Sort by age: 2(30), 1(40), 3(50) - Last sort takes precedence
715+
.sort(
716+
field("age").ascending()
717+
) // Sort by age: 2(30), 1(40), 3(50) - Last sort takes precedence
736718

737719
// The C++ test implies that the *last* sort stage defines the primary sort order.
738-
// This is different from how multiple orderBy clauses usually work in Firestore (they form a composite sort).
739-
// However, if these are separate stages, the last one would indeed re-sort the entire output of the previous.
720+
// This is different from how multiple orderBy clauses usually work in Firestore (they form a
721+
// composite sort).
722+
// However, if these are separate stages, the last one would indeed re-sort the entire output of
723+
// the previous.
740724
// Let's assume the Kotlin pipeline behaves this way for separate .orderBy() calls.
741725
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
742726
assertThat(result).containsExactly(doc2, doc1, doc3).inOrder()
@@ -760,9 +744,11 @@ internal class SortTests {
760744
assertThat(result).containsExactly(doc1, doc2, doc3).inOrder()
761745
}
762746

763-
// The C++ tests `SortOnKeyAndOtherFieldOnMultipleStages` and `SortOnOtherFieldAndKeyOnMultipleStages`
747+
// The C++ tests `SortOnKeyAndOtherFieldOnMultipleStages` and
748+
// `SortOnOtherFieldAndKeyOnMultipleStages`
764749
// are identical to the `Path` versions because `kDocumentKeyPath` is used.
765-
// These are effectively duplicates of the above two tests in Kotlin if we use `PublicFieldPath.documentId()`.
750+
// These are effectively duplicates of the above two tests in Kotlin if we use
751+
// `PublicFieldPath.documentId()`.
766752
// I'll include them for completeness, mirroring the C++ structure.
767753

768754
@Test

firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/WhereTests.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import org.robolectric.RobolectricTestRunner
4040
internal class WhereTests {
4141

4242
private val db = TestUtil.firestore()
43-
43+
4444
@Test
4545
fun `empty database returns no results`(): Unit = runBlocking {
4646
val documents = emptyList<MutableDocument>()

firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/testUtil.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,3 @@ internal fun assertEvaluatesToUnset(result: EvaluateResult, format: String, vara
6969
internal fun assertEvaluatesToError(result: EvaluateResult, format: String, vararg args: Any?) {
7070
assertWithMessage(format, *args).that(result).isSameInstanceAs(EvaluateResultError)
7171
}
72-

firebase-firestore/src/test/java/com/google/firebase/firestore/testUtil.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import com.google.firebase.firestore.pipeline.EvaluationContext
55
import kotlinx.coroutines.flow.Flow
66

77
internal fun runPipeline(
8-
db: FirebaseFirestore,
9-
pipeline: AbstractPipeline,
10-
input: Flow<MutableDocument>
8+
db: FirebaseFirestore,
9+
pipeline: AbstractPipeline,
10+
input: Flow<MutableDocument>
1111
): Flow<MutableDocument> {
1212
val context = EvaluationContext(db, db.userDataReader)
1313
return pipeline.stages.fold(input) { documentFlow, stage ->
1414
stage.evaluate(context, documentFlow)
1515
}
16-
}
16+
}

0 commit comments

Comments
 (0)