Skip to content

Commit 38b89eb

Browse files
committed
add more tests
1 parent 0f7d8ec commit 38b89eb

File tree

2 files changed

+238
-9
lines changed

2 files changed

+238
-9
lines changed

Firestore/Swift/Source/SwiftAPI/Pipeline/Expr/FunctionExpr/BooleanExpr.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ public class BooleanExpr: FunctionExpr, @unchecked Sendable {
3131
try BooleanExpr("or", [lhs, rhs()])
3232
}
3333

34+
public static func ^ (lhs: BooleanExpr,
35+
rhs: @autoclosure () throws -> BooleanExpr) rethrows -> BooleanExpr {
36+
try BooleanExpr("xor", [lhs, rhs()])
37+
}
38+
3439
public static prefix func ! (lhs: BooleanExpr) -> BooleanExpr {
3540
return BooleanExpr("not", [lhs])
3641
}

Firestore/Swift/Tests/Integration/PipelineTests.swift

Lines changed: 233 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,24 @@ func expectResults(_ snapshot: PipelineSnapshot,
237237
}
238238

239239
func expectResults(result: PipelineResult,
240-
expected: [String: Sendable],
240+
expected: [String: Sendable?],
241241
file: StaticString = #file,
242242
line: UInt = #line) {
243-
XCTAssertTrue(areDictionariesEqual(result.data, expected))
243+
XCTAssertTrue(areDictionariesEqual(result.data, expected),
244+
"Document data mismatch. Expected \(expected), got \(result.data)")
245+
}
246+
247+
func expectSnapshots(snapshot: PipelineSnapshot,
248+
expected: [[String: Sendable?]],
249+
file: StaticString = #file,
250+
line: UInt = #line) {
251+
for i in 0 ..< expected.count {
252+
guard i < snapshot.results.count else {
253+
XCTFail("Mismatch in expected results count and actual results count.")
254+
return
255+
}
256+
expectResults(result: snapshot.results[i], expected: expected[i])
257+
}
244258
}
245259

246260
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
@@ -902,13 +916,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
902916
["avgRating": 4.4, "genre": "Science Fiction"],
903917
]
904918

905-
for i in 0 ..< expectedResultsArray.count {
906-
guard i < snapshot.results.count else {
907-
XCTFail("Mismatch in expected results count and actual results count.")
908-
return
909-
}
910-
expectResults(result: snapshot.results[i], expected: expectedResultsArray[i])
911-
}
919+
expectSnapshots(snapshot: snapshot, expected: expectedResultsArray)
912920
}
913921

914922
func testReturnsMinMaxCountAndCountAllAccumulations() async throws {
@@ -962,4 +970,220 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
962970
XCTFail("No result for countIf aggregation")
963971
}
964972
}
973+
974+
func testDistinctStage() async throws {
975+
let collRef = collectionRef(withDocuments: bookDocs)
976+
let db = collRef.firestore
977+
978+
let pipeline = db.pipeline()
979+
.collection(collRef.path)
980+
.distinct(Field("genre"), Field("author"))
981+
.sort(Field("genre").ascending(), Field("author").ascending())
982+
983+
let snapshot = try await pipeline.execute()
984+
985+
let expectedResults: [[String: Sendable]] = [
986+
["genre": "Dystopian", "author": "George Orwell"],
987+
["genre": "Dystopian", "author": "Margaret Atwood"],
988+
["genre": "Fantasy", "author": "J.R.R. Tolkien"],
989+
["genre": "Magical Realism", "author": "Gabriel García Márquez"],
990+
["genre": "Modernist", "author": "F. Scott Fitzgerald"],
991+
["genre": "Psychological Thriller", "author": "Fyodor Dostoevsky"],
992+
["genre": "Romance", "author": "Jane Austen"],
993+
["genre": "Science Fiction", "author": "Douglas Adams"],
994+
["genre": "Science Fiction", "author": "Frank Herbert"],
995+
["genre": "Southern Gothic", "author": "Harper Lee"],
996+
]
997+
998+
XCTAssertEqual(snapshot.results.count, expectedResults.count, "Snapshot results count mismatch")
999+
1000+
expectSnapshots(snapshot: snapshot, expected: expectedResults)
1001+
}
1002+
1003+
func testSelectStage() async throws {
1004+
let collRef = collectionRef(withDocuments: bookDocs)
1005+
let db = collRef.firestore
1006+
1007+
let pipeline = db.pipeline()
1008+
.collection(collRef.path)
1009+
.select(Field("title"), Field("author"))
1010+
.sort(Field("author").ascending())
1011+
1012+
let snapshot = try await pipeline.execute()
1013+
1014+
let expectedResults: [[String: Sendable]] = [
1015+
["title": "The Hitchhiker's Guide to the Galaxy", "author": "Douglas Adams"],
1016+
["title": "The Great Gatsby", "author": "F. Scott Fitzgerald"],
1017+
["title": "Dune", "author": "Frank Herbert"],
1018+
["title": "Crime and Punishment", "author": "Fyodor Dostoevsky"],
1019+
["title": "One Hundred Years of Solitude", "author": "Gabriel García Márquez"],
1020+
["title": "1984", "author": "George Orwell"],
1021+
["title": "To Kill a Mockingbird", "author": "Harper Lee"],
1022+
["title": "The Lord of the Rings", "author": "J.R.R. Tolkien"],
1023+
["title": "Pride and Prejudice", "author": "Jane Austen"],
1024+
["title": "The Handmaid's Tale", "author": "Margaret Atwood"],
1025+
]
1026+
1027+
XCTAssertEqual(
1028+
snapshot.results.count,
1029+
expectedResults.count,
1030+
"Snapshot results count mismatch for select stage."
1031+
)
1032+
1033+
expectSnapshots(snapshot: snapshot, expected: expectedResults)
1034+
}
1035+
1036+
func testAddFieldStage() async throws {
1037+
let collRef = collectionRef(withDocuments: bookDocs)
1038+
let db = collRef.firestore
1039+
1040+
let pipeline = db.pipeline()
1041+
.collection(collRef.path)
1042+
.select(Field("title"), Field("author"))
1043+
.addFields(Constant("bar").as("foo"))
1044+
.sort(Field("author").ascending())
1045+
1046+
let snapshot = try await pipeline.execute()
1047+
1048+
let expectedResults: [[String: Sendable]] = [
1049+
["title": "The Hitchhiker's Guide to the Galaxy", "author": "Douglas Adams", "foo": "bar"],
1050+
["title": "The Great Gatsby", "author": "F. Scott Fitzgerald", "foo": "bar"],
1051+
["title": "Dune", "author": "Frank Herbert", "foo": "bar"],
1052+
["title": "Crime and Punishment", "author": "Fyodor Dostoevsky", "foo": "bar"],
1053+
["title": "One Hundred Years of Solitude", "author": "Gabriel García Márquez", "foo": "bar"],
1054+
["title": "1984", "author": "George Orwell", "foo": "bar"],
1055+
["title": "To Kill a Mockingbird", "author": "Harper Lee", "foo": "bar"],
1056+
["title": "The Lord of the Rings", "author": "J.R.R. Tolkien", "foo": "bar"],
1057+
["title": "Pride and Prejudice", "author": "Jane Austen", "foo": "bar"],
1058+
["title": "The Handmaid's Tale", "author": "Margaret Atwood", "foo": "bar"],
1059+
]
1060+
1061+
XCTAssertEqual(
1062+
snapshot.results.count,
1063+
expectedResults.count,
1064+
"Snapshot results count mismatch for addField stage."
1065+
)
1066+
1067+
expectSnapshots(snapshot: snapshot, expected: expectedResults)
1068+
}
1069+
1070+
func testRemoveFieldsStage() async throws {
1071+
let collRef = collectionRef(withDocuments: bookDocs)
1072+
let db = collRef.firestore
1073+
1074+
let pipeline = db.pipeline()
1075+
.collection(collRef.path)
1076+
.select(Field("title"), Field("author"))
1077+
.sort(Field("author").ascending()) // Sort before removing the 'author' field
1078+
.removeFields(Field("author"))
1079+
1080+
let snapshot = try await pipeline.execute()
1081+
1082+
// Expected results are sorted by author, but only contain the title
1083+
let expectedResults: [[String: Sendable]] = [
1084+
["title": "The Hitchhiker's Guide to the Galaxy"], // Douglas Adams
1085+
["title": "The Great Gatsby"], // F. Scott Fitzgerald
1086+
["title": "Dune"], // Frank Herbert
1087+
["title": "Crime and Punishment"], // Fyodor Dostoevsky
1088+
["title": "One Hundred Years of Solitude"], // Gabriel García Márquez
1089+
["title": "1984"], // George Orwell
1090+
["title": "To Kill a Mockingbird"], // Harper Lee
1091+
["title": "The Lord of the Rings"], // J.R.R. Tolkien
1092+
["title": "Pride and Prejudice"], // Jane Austen
1093+
["title": "The Handmaid's Tale"], // Margaret Atwood
1094+
]
1095+
1096+
XCTAssertEqual(
1097+
snapshot.results.count,
1098+
expectedResults.count,
1099+
"Snapshot results count mismatch for removeFields stage."
1100+
)
1101+
1102+
expectSnapshots(snapshot: snapshot, expected: expectedResults)
1103+
}
1104+
1105+
func testWhereStageWithAndConditions() async throws {
1106+
let collRef = collectionRef(withDocuments: bookDocs)
1107+
let db = collRef.firestore
1108+
1109+
// Test Case 1: Two AND conditions
1110+
var pipeline = db.pipeline()
1111+
.collection(collRef.path)
1112+
.where(Field("rating").gt(4.5)
1113+
&& Field("genre").eqAny(["Science Fiction", "Romance", "Fantasy"]))
1114+
var snapshot = try await pipeline.execute()
1115+
var expectedIDs = ["book10", "book4"] // Dune (SF, 4.6), LOTR (Fantasy, 4.7)
1116+
expectResults(snapshot, expectedIDs: expectedIDs)
1117+
1118+
// Test Case 2: Three AND conditions
1119+
pipeline = db.pipeline()
1120+
.collection(collRef.path)
1121+
.where(
1122+
Field("rating").gt(4.5)
1123+
&& Field("genre").eqAny(["Science Fiction", "Romance", "Fantasy"])
1124+
&& Field("published").lt(1965)
1125+
)
1126+
snapshot = try await pipeline.execute()
1127+
expectedIDs = ["book4"] // LOTR (Fantasy, 4.7, published 1954)
1128+
expectResults(snapshot, expectedIDs: expectedIDs)
1129+
}
1130+
1131+
func testWhereStageWithOrAndXorConditions() async throws {
1132+
let collRef = collectionRef(withDocuments: bookDocs)
1133+
let db = collRef.firestore
1134+
1135+
// Test Case 1: OR conditions
1136+
var pipeline = db.pipeline()
1137+
.collection(collRef.path)
1138+
.where(
1139+
Field("genre").eq("Romance")
1140+
|| Field("genre").eq("Dystopian")
1141+
|| Field("genre").eq("Fantasy")
1142+
)
1143+
.select(Field("title"))
1144+
.sort(Field("title").ascending())
1145+
1146+
var snapshot = try await pipeline.execute()
1147+
var expectedResults: [[String: Sendable]] = [
1148+
["title": "1984"], // Dystopian
1149+
["title": "Pride and Prejudice"], // Romance
1150+
["title": "The Handmaid's Tale"], // Dystopian
1151+
["title": "The Lord of the Rings"], // Fantasy
1152+
]
1153+
1154+
XCTAssertEqual(
1155+
snapshot.results.count,
1156+
expectedResults.count,
1157+
"Snapshot results count mismatch for OR conditions."
1158+
)
1159+
expectSnapshots(snapshot: snapshot, expected: expectedResults)
1160+
1161+
// Test Case 2: XOR conditions
1162+
// XOR is true if an odd number of its arguments are true.
1163+
pipeline = db.pipeline()
1164+
.collection(collRef.path)
1165+
.where(
1166+
Field("genre").eq("Romance") // Book2 (T), Book5 (F), Book4 (F), Book8 (F)
1167+
^ Field("genre").eq("Dystopian") // Book2 (F), Book5 (T), Book4 (F), Book8 (T)
1168+
^ Field("genre").eq("Fantasy") // Book2 (F), Book5 (F), Book4 (T), Book8 (F)
1169+
^ Field("published").eq(1949) // Book2 (F), Book5 (F), Book4 (F), Book8 (T)
1170+
)
1171+
.select(Field("title"))
1172+
.sort(Field("title").ascending())
1173+
1174+
snapshot = try await pipeline.execute()
1175+
1176+
expectedResults = [
1177+
["title": "Pride and Prejudice"],
1178+
["title": "The Handmaid's Tale"],
1179+
["title": "The Lord of the Rings"],
1180+
]
1181+
1182+
XCTAssertEqual(
1183+
snapshot.results.count,
1184+
expectedResults.count,
1185+
"Snapshot results count mismatch for XOR conditions."
1186+
)
1187+
expectSnapshots(snapshot: snapshot, expected: expectedResults)
1188+
}
9651189
}

0 commit comments

Comments
 (0)