Skip to content

Commit 4fcdf17

Browse files
committed
Unicode Tests
1 parent 2708d15 commit 4fcdf17

File tree

1 file changed

+111
-0
lines changed
  • firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline

1 file changed

+111
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.firestore.pipeline
16+
17+
import com.google.common.truth.Truth.assertThat
18+
import com.google.firebase.firestore.RealtimePipelineSource
19+
import com.google.firebase.firestore.TestUtil
20+
import com.google.firebase.firestore.pipeline.Expr.Companion.and
21+
import com.google.firebase.firestore.pipeline.Expr.Companion.constant
22+
import com.google.firebase.firestore.pipeline.Expr.Companion.field
23+
import com.google.firebase.firestore.runPipeline
24+
import com.google.firebase.firestore.testutil.TestUtilKtx.doc
25+
import kotlinx.coroutines.flow.flowOf
26+
import kotlinx.coroutines.flow.toList
27+
import kotlinx.coroutines.runBlocking
28+
import org.junit.Test
29+
import org.junit.runner.RunWith
30+
import org.robolectric.RobolectricTestRunner
31+
32+
@RunWith(RobolectricTestRunner::class)
33+
internal class UnicodeTests {
34+
35+
private val db = TestUtil.firestore()
36+
37+
@Test
38+
fun `basic unicode`(): Unit = runBlocking {
39+
val doc1 = doc("🐵/Łukasiewicz", 1000, mapOf("Ł" to "Jan Łukasiewicz"))
40+
val doc2 = doc("🐵/Sierpiński", 1000, mapOf("Ł" to "Wacław Sierpiński"))
41+
val doc3 = doc("🐵/iwasawa", 1000, mapOf("Ł" to "岩澤"))
42+
43+
val documents = listOf(doc1, doc2, doc3)
44+
val pipeline = RealtimePipelineSource(db).collection("/🐵").sort(field("Ł").ascending())
45+
46+
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
47+
assertThat(result).containsExactly(doc1, doc2, doc3).inOrder()
48+
}
49+
50+
@Test
51+
fun `unicode surrogates`(): Unit = runBlocking {
52+
val doc1 = doc("users/a", 1000, mapOf("str" to "🄟"))
53+
val doc2 = doc("users/b", 1000, mapOf("str" to ""))
54+
val doc3 =
55+
doc("users/c", 1000, mapOf("str" to "")) // This char is U+FE12, sorts before P and 🄟
56+
57+
val documents = listOf(doc1, doc2, doc3)
58+
val pipeline =
59+
RealtimePipelineSource(db)
60+
.collection("users") // C++ uses DatabaseSource, "users" collection matches doc paths
61+
.where(
62+
and(
63+
field("str").lte(constant("🄟")),
64+
field("str").gte(constant("")),
65+
)
66+
)
67+
.sort(field("str").ascending())
68+
69+
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
70+
assertThat(result).containsExactly(doc2, doc1).inOrder()
71+
}
72+
73+
@Test
74+
fun `unicode surrogates in array`(): Unit = runBlocking {
75+
val doc1 = doc("users/a", 1000, mapOf("foo" to listOf("🄟")))
76+
val doc2 = doc("users/b", 1000, mapOf("foo" to listOf("")))
77+
val doc3 = doc("users/c", 1000, mapOf("foo" to listOf("")))
78+
79+
val documents = listOf(doc1, doc2, doc3)
80+
val pipeline = RealtimePipelineSource(db).collection("users").sort(field("foo").ascending())
81+
82+
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
83+
assertThat(result).containsExactly(doc3, doc2, doc1).inOrder()
84+
}
85+
86+
@Test
87+
fun `unicode surrogates in map keys`(): Unit = runBlocking {
88+
val doc1 = doc("users/a", 1000, mapOf("map" to mapOf("" to true, "z" to true)))
89+
val doc2 = doc("users/b", 1000, mapOf("map" to mapOf("🄟" to true, "" to true)))
90+
val doc3 = doc("users/c", 1000, mapOf("map" to mapOf("" to true, "" to true)))
91+
92+
val documents = listOf(doc1, doc2, doc3)
93+
val pipeline = RealtimePipelineSource(db).collection("users").sort(field("map").ascending())
94+
95+
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
96+
assertThat(result).containsExactly(doc1, doc3, doc2).inOrder()
97+
}
98+
99+
@Test
100+
fun `unicode surrogates in map values`(): Unit = runBlocking {
101+
val doc1 = doc("users/a", 1000, mapOf("map" to mapOf("foo" to "")))
102+
val doc2 = doc("users/b", 1000, mapOf("map" to mapOf("foo" to "🄟")))
103+
val doc3 = doc("users/c", 1000, mapOf("map" to mapOf("foo" to "")))
104+
105+
val documents = listOf(doc1, doc2, doc3)
106+
val pipeline = RealtimePipelineSource(db).collection("users").sort(field("map").ascending())
107+
108+
val result = runPipeline(db, pipeline, flowOf(*documents.toTypedArray())).toList()
109+
assertThat(result).containsExactly(doc1, doc3, doc2).inOrder()
110+
}
111+
}

0 commit comments

Comments
 (0)