Podfile tweaks to speed up sim builds, unit tests & minor bug fix
Added a patch to the Podfile to avoid rsync'ing and signing WebRTC-lib for simulator builds shaving off 10+ seconds of build time per target due to the sheer size of the WebRTC debug framework Added some basic unit tests to validate the current search behaviour Fixed some buggy search behaviours
This commit is contained in:
parent
3151aa8901
commit
0225f436bd
10
Podfile
10
Podfile
|
@ -101,6 +101,7 @@ end
|
|||
# Actions to perform post-install
|
||||
post_install do |installer|
|
||||
set_minimum_deployment_target(installer)
|
||||
avoid_rsync_webrtc_if_unchanged(installer)
|
||||
end
|
||||
|
||||
def set_minimum_deployment_target(installer)
|
||||
|
@ -110,3 +111,12 @@ def set_minimum_deployment_target(installer)
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This function patches the Cocoapods 'Embed Frameworks' script to avoid running rsync
|
||||
# for the WebRTC-lib framework in simulator builds if it has already been copied over
|
||||
# because due to the size it can take over 10 seconds to embed, and gets embeded in
|
||||
# each target on every build regardless of whether there were changes, drastically
|
||||
# increasing the length of the build
|
||||
def avoid_rsync_webrtc_if_unchanged(installer)
|
||||
system('find "./Pods/Target Support Files" -name "*-frameworks.sh" -exec patch -p0 -i ./Scripts/skip_web_rtc_re_rsync.patch {} \;')
|
||||
end
|
||||
|
|
|
@ -204,6 +204,6 @@ SPEC CHECKSUMS:
|
|||
YYImage: f1ddd15ac032a58b78bbed1e012b50302d318331
|
||||
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
|
||||
|
||||
PODFILE CHECKSUM: 68799237a4dc046f5ac25c573af03b559f5b10c4
|
||||
PODFILE CHECKSUM: dcca0c4ad69b14cbc2d6ba49f9d690b239828e6d
|
||||
|
||||
COCOAPODS: 1.12.1
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
@@ -41,0 +41,11 @@
|
||||
+ # Skip the rsync step for the WebRTC-lib in simulator builds
|
||||
+ if [[ "$PLATFORM_NAME" == "iphonesimulator" ]] && [[ "$source" == *WebRTC.framework* ]]; then
|
||||
+ if [[ -f "${source}/../already_rsynced.nonce" ]]; then
|
||||
+ echo "Already rsynced WebRTC, skipping"
|
||||
+ return 0
|
||||
+ fi
|
||||
+
|
||||
+ echo "About to rsync a simulator WebRTC, creating nonce to prevent future rsyncing"
|
||||
+ touch "${source}/../already_rsynced.nonce"
|
||||
+ fi
|
||||
+
|
|
@ -696,6 +696,7 @@
|
|||
FD716E6C28505E1C00C96BF4 /* MessageRequestsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD716E6B28505E1C00C96BF4 /* MessageRequestsViewModel.swift */; };
|
||||
FD716E7128505E5200C96BF4 /* MessageRequestsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD716E7028505E5100C96BF4 /* MessageRequestsCell.swift */; };
|
||||
FD716E722850647600C96BF4 /* Data+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD859EF127BF6BA200510D0C /* Data+Utilities.swift */; };
|
||||
FD7692F72A53A2ED000E4B70 /* SessionThreadViewModelSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7692F62A53A2ED000E4B70 /* SessionThreadViewModelSpec.swift */; };
|
||||
FD7728962849E7E90018502F /* String+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7728952849E7E90018502F /* String+Utilities.swift */; };
|
||||
FD7728982849E8110018502F /* UITableView+ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7728972849E8110018502F /* UITableView+ReusableView.swift */; };
|
||||
FD77289A284AF1BD0018502F /* Sodium+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD772899284AF1BD0018502F /* Sodium+Utilities.swift */; };
|
||||
|
@ -1828,6 +1829,7 @@
|
|||
FD716E692850327900C96BF4 /* EndCallMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndCallMode.swift; sourceTree = "<group>"; };
|
||||
FD716E6B28505E1C00C96BF4 /* MessageRequestsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRequestsViewModel.swift; sourceTree = "<group>"; };
|
||||
FD716E7028505E5100C96BF4 /* MessageRequestsCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRequestsCell.swift; sourceTree = "<group>"; };
|
||||
FD7692F62A53A2ED000E4B70 /* SessionThreadViewModelSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionThreadViewModelSpec.swift; sourceTree = "<group>"; };
|
||||
FD7728952849E7E90018502F /* String+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Utilities.swift"; sourceTree = "<group>"; };
|
||||
FD7728972849E8110018502F /* UITableView+ReusableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITableView+ReusableView.swift"; sourceTree = "<group>"; };
|
||||
FD772899284AF1BD0018502F /* Sodium+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Sodium+Utilities.swift"; sourceTree = "<group>"; };
|
||||
|
@ -3316,10 +3318,10 @@
|
|||
B8DE1FB226C22F1F0079C9CE /* Calls */,
|
||||
C32C5BCB256DC818003C73A2 /* Database */,
|
||||
C300A5BB2554AFFB00555489 /* Messages */,
|
||||
C300A5F02554B08500555489 /* Sending & Receiving */,
|
||||
C352A2F325574B3300338F3E /* Jobs */,
|
||||
C3A7215C2558C0AC0043A11F /* File Server */,
|
||||
C3A721332558BDDF0043A11F /* Open Groups */,
|
||||
C300A5F02554B08500555489 /* Sending & Receiving */,
|
||||
FD8ECF7529340F4800C0D1BB /* SessionUtil */,
|
||||
FD3E0C82283B581F002A425C /* Shared Models */,
|
||||
C3BBE0B32554F0D30050F1E3 /* Utilities */,
|
||||
|
@ -3994,6 +3996,14 @@
|
|||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FD7692F52A53A2C7000E4B70 /* Shared Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FD7692F62A53A2ED000E4B70 /* SessionThreadViewModelSpec.swift */,
|
||||
);
|
||||
path = "Shared Models";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FD7728A1284F0DF50018502F /* Message Handling */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -4224,6 +4234,7 @@
|
|||
FD3C906527E416A200CD579F /* Contacts */,
|
||||
FDC4389827BA001800C60D73 /* Open Groups */,
|
||||
FD3C906B27E43C2400CD579F /* Sending & Receiving */,
|
||||
FD7692F52A53A2C7000E4B70 /* Shared Models */,
|
||||
FD3C906827E417B100CD579F /* Utilities */,
|
||||
FD8ECF802934385900C0D1BB /* LibSessionUtil */,
|
||||
);
|
||||
|
@ -6391,6 +6402,7 @@
|
|||
FDC2908B27D707F3005DAE71 /* SendMessageRequestSpec.swift in Sources */,
|
||||
FD8ECF822934387A00C0D1BB /* ConfigUserProfileSpec.swift in Sources */,
|
||||
FDC290A827D9B46D005DAE71 /* NimbleExtensions.swift in Sources */,
|
||||
FD7692F72A53A2ED000E4B70 /* SessionThreadViewModelSpec.swift in Sources */,
|
||||
FDC2908F27D70938005DAE71 /* SendDirectMessageRequestSpec.swift in Sources */,
|
||||
FDC438BD27BB2AB400C60D73 /* Mockable.swift in Sources */,
|
||||
FDA1E83929A5771A00C5C3BD /* LibSessionSpec.swift in Sources */,
|
||||
|
|
|
@ -1979,8 +1979,7 @@ extension ConversationVC:
|
|||
self?.showInputAccessoryView()
|
||||
})
|
||||
|
||||
self.inputAccessoryView?.isHidden = true
|
||||
self.inputAccessoryView?.alpha = 0
|
||||
self.hideInputAccessoryView()
|
||||
Modal.setupForIPadIfNeeded(actionSheet, targetView: self.view)
|
||||
self.present(actionSheet, animated: true)
|
||||
}
|
||||
|
|
|
@ -106,6 +106,7 @@ class MessageRequestsViewController: BaseVC, SessionUtilRespondingViewController
|
|||
result.translatesAutoresizingMaskIntoConstraints = false
|
||||
result.setTitle("MESSAGE_REQUESTS_CLEAR_ALL".localized(), for: .normal)
|
||||
result.addTarget(self, action: #selector(clearAllTapped), for: .touchUpInside)
|
||||
result.accessibilityIdentifier = "Clear all"
|
||||
|
||||
return result
|
||||
}()
|
||||
|
|
|
@ -1112,19 +1112,22 @@ public extension SessionThreadViewModel {
|
|||
/// Step 2 - Separate any words outside of quotes
|
||||
/// Step 3 - Join the different search term parts with 'OR" (include results for each individual term)
|
||||
/// Step 4 - Append a wild-card character to the final word (as long as the last word doesn't end in a quote)
|
||||
return standardQuotes(searchTerm)
|
||||
.split(separator: "\"")
|
||||
.enumerated()
|
||||
.flatMap { index, value -> [String] in
|
||||
guard index % 2 == 1 else {
|
||||
return String(value)
|
||||
.split(separator: " ")
|
||||
.map { "\"\(String($0))\"" }
|
||||
}
|
||||
|
||||
return ["\"\(value)\""]
|
||||
}
|
||||
.filter { !$0.isEmpty }
|
||||
let normalisedTerm: String = standardQuotes(searchTerm)
|
||||
|
||||
guard let regex = try? NSRegularExpression(pattern: "[^\\s\"']+|\"([^\"]*)\"") else {
|
||||
// Fallback to removing the quotes and just splitting on spaces
|
||||
return normalisedTerm
|
||||
.replacingOccurrences(of: "\"", with: "")
|
||||
.split(separator: " ")
|
||||
.map { "\"\($0)\"" }
|
||||
.filter { !$0.isEmpty }
|
||||
}
|
||||
|
||||
return regex
|
||||
.matches(in: normalisedTerm, range: NSRange(location: 0, length: normalisedTerm.count))
|
||||
.compactMap { Range($0.range, in: normalisedTerm) }
|
||||
.map { normalisedTerm[$0].trimmingCharacters(in: CharacterSet(charactersIn: "\"")) }
|
||||
.map { "\"\($0)\"" }
|
||||
}
|
||||
|
||||
static func standardQuotes(_ term: String) -> String {
|
||||
|
@ -1155,15 +1158,17 @@ public extension SessionThreadViewModel {
|
|||
|
||||
/// There are cases where creating a pattern can fail, we want to try and recover from those cases
|
||||
/// by failling back to simpler patterns if needed
|
||||
let maybePattern: FTS5Pattern? = (try? db.makeFTS5Pattern(rawPattern: rawPattern, forTable: table))
|
||||
.defaulting(
|
||||
to: (try? db.makeFTS5Pattern(rawPattern: fallbackTerm, forTable: table))
|
||||
.defaulting(to: FTS5Pattern(matchingAnyTokenIn: fallbackTerm))
|
||||
)
|
||||
|
||||
guard let pattern: FTS5Pattern = maybePattern else { throw StorageError.invalidSearchPattern }
|
||||
|
||||
return pattern
|
||||
return try {
|
||||
if let pattern: FTS5Pattern = try? db.makeFTS5Pattern(rawPattern: rawPattern, forTable: table) {
|
||||
return pattern
|
||||
}
|
||||
|
||||
if let pattern: FTS5Pattern = try? db.makeFTS5Pattern(rawPattern: fallbackTerm, forTable: table) {
|
||||
return pattern
|
||||
}
|
||||
|
||||
return try FTS5Pattern(matchingAnyTokenIn: fallbackTerm) ?? { throw StorageError.invalidSearchPattern }()
|
||||
}()
|
||||
}
|
||||
|
||||
static func messagesQuery(userPublicKey: String, pattern: FTS5Pattern) -> AdaptedFetchRequest<SQLRequest<SessionThreadViewModel>> {
|
||||
|
|
|
@ -0,0 +1,334 @@
|
|||
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import Quick
|
||||
import Nimble
|
||||
import SessionUtilitiesKit
|
||||
|
||||
@testable import SessionMessagingKit
|
||||
|
||||
class SessionThreadViewModelSpec: QuickSpec {
|
||||
public struct TestMessage: Codable, Equatable, FetchableRecord, PersistableRecord, TableRecord, ColumnExpressible {
|
||||
public static var databaseTableName: String { "testMessage" }
|
||||
|
||||
public typealias Columns = CodingKeys
|
||||
public enum CodingKeys: String, CodingKey, ColumnExpression {
|
||||
case body
|
||||
}
|
||||
|
||||
public let body: String
|
||||
}
|
||||
|
||||
// MARK: - Spec
|
||||
|
||||
override func spec() {
|
||||
describe("a SessionThreadViewModel") {
|
||||
var mockStorage: Storage!
|
||||
|
||||
beforeEach {
|
||||
mockStorage = SynchronousStorage(
|
||||
customWriter: try! DatabaseQueue()
|
||||
)
|
||||
|
||||
mockStorage.write { db in
|
||||
try db.create(table: TestMessage.self) { t in
|
||||
t.column(.body, .text).notNull()
|
||||
}
|
||||
|
||||
try db.create(virtualTable: TestMessage.fullTextSearchTableName, using: FTS5()) { t in
|
||||
t.synchronize(withTable: TestMessage.databaseTableName)
|
||||
t.tokenizer = .porter(wrapping: .unicode61())
|
||||
|
||||
t.column(TestMessage.Columns.body.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - when processing a search term
|
||||
context("when processing a search term") {
|
||||
// MARK: -- correctly generates a safe search term
|
||||
it("correctly generates a safe search term") {
|
||||
expect(SessionThreadViewModel.searchSafeTerm("Test")).to(equal("\"Test\""))
|
||||
}
|
||||
|
||||
// MARK: -- standardises odd quote characters
|
||||
it("standardises odd quote characters") {
|
||||
expect(SessionThreadViewModel.standardQuotes("\"")).to(equal("\""))
|
||||
expect(SessionThreadViewModel.standardQuotes("”")).to(equal("\""))
|
||||
expect(SessionThreadViewModel.standardQuotes("“")).to(equal("\""))
|
||||
}
|
||||
|
||||
// MARK: -- splits on the space character
|
||||
it("splits on the space character") {
|
||||
expect(SessionThreadViewModel.searchTermParts("Test Message"))
|
||||
.to(equal([
|
||||
"\"Test\"",
|
||||
"\"Message\""
|
||||
]))
|
||||
}
|
||||
|
||||
// MARK: -- surrounds each split term with quotes
|
||||
it("surrounds each split term with quotes") {
|
||||
expect(SessionThreadViewModel.searchTermParts("Test Message"))
|
||||
.to(equal([
|
||||
"\"Test\"",
|
||||
"\"Message\""
|
||||
]))
|
||||
}
|
||||
|
||||
// MARK: -- keeps words within quotes together
|
||||
it("keeps words within quotes together") {
|
||||
expect(SessionThreadViewModel.searchTermParts("This \"is a Test\" Message"))
|
||||
.to(equal([
|
||||
"\"This\"",
|
||||
"\"is a Test\"",
|
||||
"\"Message\""
|
||||
]))
|
||||
expect(SessionThreadViewModel.searchTermParts("\"This is\" a Test Message"))
|
||||
.to(equal([
|
||||
"\"This is\"",
|
||||
"\"a\"",
|
||||
"\"Test\"",
|
||||
"\"Message\""
|
||||
]))
|
||||
expect(SessionThreadViewModel.searchTermParts("\"This is\" \"a Test\" Message"))
|
||||
.to(equal([
|
||||
"\"This is\"",
|
||||
"\"a Test\"",
|
||||
"\"Message\""
|
||||
]))
|
||||
expect(SessionThreadViewModel.searchTermParts("\"This is\" a \"Test Message\""))
|
||||
.to(equal([
|
||||
"\"This is\"",
|
||||
"\"a\"",
|
||||
"\"Test Message\""
|
||||
]))
|
||||
expect(SessionThreadViewModel.searchTermParts("\"This is\"\" a \"Test Message"))
|
||||
.to(equal([
|
||||
"\"This is\"",
|
||||
"\" a \"",
|
||||
"\"Test\"",
|
||||
"\"Message\""
|
||||
]))
|
||||
}
|
||||
|
||||
// MARK: -- keeps words within weird quotes together
|
||||
it("keeps words within weird quotes together") {
|
||||
expect(SessionThreadViewModel.searchTermParts("This ”is a Test“ Message"))
|
||||
.to(equal([
|
||||
"\"This\"",
|
||||
"\"is a Test\"",
|
||||
"\"Message\""
|
||||
]))
|
||||
}
|
||||
|
||||
// MARK: -- removes extra whitespace
|
||||
it("removes extra whitespace") {
|
||||
expect(SessionThreadViewModel.searchTermParts(" Test Message "))
|
||||
.to(equal([
|
||||
"\"Test\"",
|
||||
"\"Message\""
|
||||
]))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - when searching
|
||||
context("when searching") {
|
||||
beforeEach {
|
||||
mockStorage.write { db in
|
||||
try TestMessage(body: "Test").insert(db)
|
||||
try TestMessage(body: "Test123").insert(db)
|
||||
try TestMessage(body: "Test234").insert(db)
|
||||
try TestMessage(body: "Test Test123").insert(db)
|
||||
try TestMessage(body: "Test Test123 Test234").insert(db)
|
||||
try TestMessage(body: "Test Test234").insert(db)
|
||||
try TestMessage(body: "Test Test234 Test123").insert(db)
|
||||
try TestMessage(body: "This is a Test Message").insert(db)
|
||||
try TestMessage(body: "is a Message This Test").insert(db)
|
||||
try TestMessage(body: "this message is a test").insert(db)
|
||||
try TestMessage(
|
||||
body: "This content is something which includes a combination of test words found in another message"
|
||||
)
|
||||
.insert(db)
|
||||
try TestMessage(body: "Do test messages contain content?").insert(db)
|
||||
try TestMessage(body: "Is messaging awesome?").insert(db)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -- returns results
|
||||
it("returns results") {
|
||||
let results = mockStorage.read { db in
|
||||
let pattern: FTS5Pattern = try SessionThreadViewModel.pattern(
|
||||
db,
|
||||
searchTerm: "Message",
|
||||
forTable: TestMessage.self
|
||||
)
|
||||
|
||||
return try SQLRequest<TestMessage>(literal: """
|
||||
SELECT *
|
||||
FROM testMessage
|
||||
JOIN testMessage_fts ON (
|
||||
testMessage_fts.rowId = testMessage.rowId AND
|
||||
testMessage_fts.body MATCH \(pattern)
|
||||
)
|
||||
""").fetchAll(db)
|
||||
}
|
||||
|
||||
expect(results)
|
||||
.to(equal([
|
||||
TestMessage(body: "This is a Test Message"),
|
||||
TestMessage(body: "is a Message This Test"),
|
||||
TestMessage(body: "this message is a test"),
|
||||
TestMessage(body: "This content is something which includes a combination of test words found in another message"),
|
||||
TestMessage(body: "Do test messages contain content?"),
|
||||
TestMessage(body: "Is messaging awesome?")
|
||||
]))
|
||||
}
|
||||
|
||||
// MARK: -- adds a wildcard to the final part
|
||||
it("adds a wildcard to the final part") {
|
||||
let results = mockStorage.read { db in
|
||||
let pattern: FTS5Pattern = try SessionThreadViewModel.pattern(
|
||||
db,
|
||||
searchTerm: "This mes",
|
||||
forTable: TestMessage.self
|
||||
)
|
||||
|
||||
return try SQLRequest<TestMessage>(literal: """
|
||||
SELECT *
|
||||
FROM testMessage
|
||||
JOIN testMessage_fts ON (
|
||||
testMessage_fts.rowId = testMessage.rowId AND
|
||||
testMessage_fts.body MATCH \(pattern)
|
||||
)
|
||||
""").fetchAll(db)
|
||||
}
|
||||
|
||||
expect(results)
|
||||
.to(equal([
|
||||
TestMessage(body: "This is a Test Message"),
|
||||
TestMessage(body: "is a Message This Test"),
|
||||
TestMessage(body: "this message is a test"),
|
||||
TestMessage(body: "This content is something which includes a combination of test words found in another message"),
|
||||
TestMessage(body: "Do test messages contain content?"),
|
||||
TestMessage(body: "Is messaging awesome?")
|
||||
]))
|
||||
}
|
||||
|
||||
// MARK: -- does not add a wildcard to other parts
|
||||
it("does not add a wildcard to other parts") {
|
||||
let results = mockStorage.read { db in
|
||||
let pattern: FTS5Pattern = try SessionThreadViewModel.pattern(
|
||||
db,
|
||||
searchTerm: "mes Random",
|
||||
forTable: TestMessage.self
|
||||
)
|
||||
|
||||
return try SQLRequest<TestMessage>(literal: """
|
||||
SELECT *
|
||||
FROM testMessage
|
||||
JOIN testMessage_fts ON (
|
||||
testMessage_fts.rowId = testMessage.rowId AND
|
||||
testMessage_fts.body MATCH \(pattern)
|
||||
)
|
||||
""").fetchAll(db)
|
||||
}
|
||||
|
||||
expect(results)
|
||||
.to(beEmpty())
|
||||
}
|
||||
|
||||
// MARK: -- finds similar words without the wildcard due to the porter tokenizer
|
||||
it("finds similar words without the wildcard due to the porter tokenizer") {
|
||||
let results = mockStorage.read { db in
|
||||
let pattern: FTS5Pattern = try SessionThreadViewModel.pattern(
|
||||
db,
|
||||
searchTerm: "message z",
|
||||
forTable: TestMessage.self
|
||||
)
|
||||
|
||||
return try SQLRequest<TestMessage>(literal: """
|
||||
SELECT *
|
||||
FROM testMessage
|
||||
JOIN testMessage_fts ON (
|
||||
testMessage_fts.rowId = testMessage.rowId AND
|
||||
testMessage_fts.body MATCH \(pattern)
|
||||
)
|
||||
""").fetchAll(db)
|
||||
}
|
||||
|
||||
expect(results)
|
||||
.to(equal([
|
||||
TestMessage(body: "This is a Test Message"),
|
||||
TestMessage(body: "is a Message This Test"),
|
||||
TestMessage(body: "this message is a test"),
|
||||
TestMessage(
|
||||
body: "This content is something which includes a combination of test words found in another message"
|
||||
),
|
||||
TestMessage(body: "Do test messages contain content?"),
|
||||
TestMessage(body: "Is messaging awesome?")
|
||||
]))
|
||||
}
|
||||
|
||||
// MARK: -- finds results containing the words regardless of the order
|
||||
it("finds results containing the words regardless of the order") {
|
||||
let results = mockStorage.read { db in
|
||||
let pattern: FTS5Pattern = try SessionThreadViewModel.pattern(
|
||||
db,
|
||||
searchTerm: "is a message",
|
||||
forTable: TestMessage.self
|
||||
)
|
||||
|
||||
return try SQLRequest<TestMessage>(literal: """
|
||||
SELECT *
|
||||
FROM testMessage
|
||||
JOIN testMessage_fts ON (
|
||||
testMessage_fts.rowId = testMessage.rowId AND
|
||||
testMessage_fts.body MATCH \(pattern)
|
||||
)
|
||||
""").fetchAll(db)
|
||||
}
|
||||
|
||||
expect(results)
|
||||
.to(equal([
|
||||
TestMessage(body: "This is a Test Message"),
|
||||
TestMessage(body: "is a Message This Test"),
|
||||
TestMessage(body: "this message is a test"),
|
||||
TestMessage(
|
||||
body: "This content is something which includes a combination of test words found in another message"
|
||||
),
|
||||
TestMessage(body: "Do test messages contain content?"),
|
||||
TestMessage(body: "Is messaging awesome?")
|
||||
]))
|
||||
}
|
||||
|
||||
// MARK: -- does not find quoted parts out of order
|
||||
it("does not find quoted parts out of order") {
|
||||
let results = mockStorage.read { db in
|
||||
let pattern: FTS5Pattern = try SessionThreadViewModel.pattern(
|
||||
db,
|
||||
searchTerm: "\"this is a\" \"test message\"",
|
||||
forTable: TestMessage.self
|
||||
)
|
||||
|
||||
return try SQLRequest<TestMessage>(literal: """
|
||||
SELECT *
|
||||
FROM testMessage
|
||||
JOIN testMessage_fts ON (
|
||||
testMessage_fts.rowId = testMessage.rowId AND
|
||||
testMessage_fts.body MATCH \(pattern)
|
||||
)
|
||||
""").fetchAll(db)
|
||||
}
|
||||
|
||||
expect(results)
|
||||
.to(equal([
|
||||
TestMessage(body: "This is a Test Message"),
|
||||
TestMessage(body: "Do test messages contain content?")
|
||||
]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@ import Combine
|
|||
import GRDB
|
||||
import Quick
|
||||
import Nimble
|
||||
import SessionUIKit
|
||||
import SessionSnodeKit
|
||||
|
||||
@testable import Session
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ import Combine
|
|||
import GRDB
|
||||
import Quick
|
||||
import Nimble
|
||||
import SessionUIKit
|
||||
import SessionSnodeKit
|
||||
|
||||
@testable import Session
|
||||
|
||||
|
|
Loading…
Reference in New Issue