mirror of https://github.com/oxen-io/session-ios
Merge branch 'updated-user-config-handling' into disappearing-message-redesign
commit
0b0371e769
@ -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
|
||||||
|
+
|
@ -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?")
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue