An amazing project that generates micro reports from tournament results
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

293 lines
13 KiB

////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
import XCTest
import RealmSwift
class ThreadSafeReferenceTests: TestCase {
/// Resolve a thread-safe reference confirming that you can't resolve it a second time.
func assertResolve<T>(_ realm: Realm, _ reference: ThreadSafeReference<T>) -> T? {
XCTAssertFalse(reference.isInvalidated)
let object = realm.resolve(reference)
XCTAssert(reference.isInvalidated)
assertThrows(realm.resolve(reference), reason: "Can only resolve a thread safe reference once")
return object
}
func testInvalidThreadSafeReferenceConstruction() {
let stringObject = SwiftStringObject()
let arrayParent = SwiftArrayPropertyObject(value: ["arrayObject", [["a"]], []])
let arrayObject = arrayParent.array
assertThrows(ThreadSafeReference(to: stringObject), reason: "Cannot construct reference to unmanaged object")
assertThrows(ThreadSafeReference(to: arrayObject), reason: "Cannot construct reference to unmanaged object")
let realm = try! Realm()
realm.beginWrite()
realm.add(stringObject)
realm.add(arrayParent)
realm.deleteAll()
try! realm.commitWrite()
assertThrows(ThreadSafeReference(to: stringObject), reason: "Cannot construct reference to invalidated object")
assertThrows(ThreadSafeReference(to: arrayObject), reason: "Cannot construct reference to invalidated object")
}
func testInvalidThreadSafeReferenceUsage() {
let realm = try! Realm()
realm.beginWrite()
let stringObject = realm.create(SwiftStringObject.self, value: ["stringCol": "hello"])
assertThrows(ThreadSafeReference(to: stringObject),
reason: "Cannot obtain thread safe reference during a write transaction")
try! realm.commitWrite()
let ref1 = ThreadSafeReference(to: stringObject)
let ref2 = ThreadSafeReference(to: stringObject)
let ref3 = ThreadSafeReference(to: stringObject)
dispatchSyncNewThread {
self.assertThrows(self.realmWithTestPath().resolve(ref1),
reason: "Cannot resolve thread safe reference in Realm with different configuration than the source Realm")
let realm = try! Realm()
realm.beginWrite()
self.assertThrows(realm.resolve(ref2),
reason: "Cannot resolve thread safe reference during a write transaction")
self.assertThrows(realm.resolve(ref2),
reason: "Can only resolve a thread safe reference once")
realm.cancelWrite()
self.assertThrows(realm.resolve(ref2),
reason: "Can only resolve a thread safe reference once")
// Assert that we can resolve a different reference to the same object.
XCTAssertEqual(self.assertResolve(realm, ref3)!.stringCol, "hello")
}
}
func testPassThreadSafeReferenceToDeletedObject() {
let realm = try! Realm()
let intObject = SwiftIntObject()
try! realm.write {
realm.add(intObject)
}
let ref1 = ThreadSafeReference(to: intObject)
let ref2 = ThreadSafeReference(to: intObject)
XCTAssertEqual(0, intObject.intCol)
try! realm.write {
realm.delete(intObject)
}
dispatchSyncNewThread {
let realm = try! Realm()
XCTAssertEqual(self.assertResolve(realm, ref1)!.intCol, 0)
realm.refresh()
XCTAssertNil(self.assertResolve(realm, ref2))
}
}
func testPassThreadSafeReferencesToMultipleObjects() {
let realm = try! Realm()
let (stringObject, intObject) = (SwiftStringObject(), SwiftIntObject())
try! realm.write {
realm.add(stringObject)
realm.add(intObject)
}
let stringObjectRef = ThreadSafeReference(to: stringObject)
let intObjectRef = ThreadSafeReference(to: intObject)
XCTAssertEqual("", stringObject.stringCol)
XCTAssertEqual(0, intObject.intCol)
dispatchSyncNewThread {
let realm = try! Realm()
let stringObject = self.assertResolve(realm, stringObjectRef)!
let intObject = self.assertResolve(realm, intObjectRef)!
try! realm.write {
stringObject.stringCol = "the meaning of life"
intObject.intCol = 42
}
}
XCTAssertEqual("", stringObject.stringCol)
XCTAssertEqual(0, intObject.intCol)
realm.refresh()
XCTAssertEqual("the meaning of life", stringObject.stringCol)
XCTAssertEqual(42, intObject.intCol)
}
func testPassThreadSafeReferenceToList() {
let realm = try! Realm()
let company = SwiftCompanyObject()
try! realm.write {
realm.add(company)
company.employees.append(SwiftEmployeeObject(value: ["name": "jg"]))
}
XCTAssertEqual(1, company.employees.count)
XCTAssertEqual("jg", company.employees[0].name)
let listRef = ThreadSafeReference(to: company.employees)
dispatchSyncNewThread {
let realm = try! Realm()
let employees = self.assertResolve(realm, listRef)!
XCTAssertEqual(1, employees.count)
XCTAssertEqual("jg", employees[0].name)
try! realm.write {
employees.removeAll()
employees.append(SwiftEmployeeObject(value: ["name": "jp"]))
employees.append(SwiftEmployeeObject(value: ["name": "az"]))
}
XCTAssertEqual(2, employees.count)
XCTAssertEqual("jp", employees[0].name)
XCTAssertEqual("az", employees[1].name)
}
XCTAssertEqual(1, company.employees.count)
XCTAssertEqual("jg", company.employees[0].name)
realm.refresh()
XCTAssertEqual(2, company.employees.count)
XCTAssertEqual("jp", company.employees[0].name)
XCTAssertEqual("az", company.employees[1].name)
}
func testPassThreadSafeReferenceToResults() {
let realm = try! Realm()
let allObjects = realm.objects(SwiftStringObject.self)
let results = allObjects
.filter("stringCol != 'C'")
.sorted(byKeyPath: "stringCol", ascending: false)
let resultsRef = ThreadSafeReference(to: results)
try! realm.write {
realm.create(SwiftStringObject.self, value: ["A"])
realm.create(SwiftStringObject.self, value: ["B"])
realm.create(SwiftStringObject.self, value: ["C"])
realm.create(SwiftStringObject.self, value: ["D"])
}
XCTAssertEqual(4, allObjects.count)
XCTAssertEqual(3, results.count)
XCTAssertEqual("D", results[0].stringCol)
XCTAssertEqual("B", results[1].stringCol)
XCTAssertEqual("A", results[2].stringCol)
dispatchSyncNewThread {
let realm = try! Realm()
let results = self.assertResolve(realm, resultsRef)!
let allObjects = realm.objects(SwiftStringObject.self)
XCTAssertEqual(0, allObjects.count)
XCTAssertEqual(0, results.count)
realm.refresh()
XCTAssertEqual(4, allObjects.count)
XCTAssertEqual(3, results.count)
XCTAssertEqual("D", results[0].stringCol)
XCTAssertEqual("B", results[1].stringCol)
XCTAssertEqual("A", results[2].stringCol)
try! realm.write {
realm.delete(results[2])
realm.delete(results[0])
realm.create(SwiftStringObject.self, value: ["E"])
}
XCTAssertEqual(3, allObjects.count)
XCTAssertEqual(2, results.count)
XCTAssertEqual("E", results[0].stringCol)
XCTAssertEqual("B", results[1].stringCol)
}
XCTAssertEqual(4, allObjects.count)
XCTAssertEqual(3, results.count)
XCTAssertEqual("D", results[0].stringCol)
XCTAssertEqual("B", results[1].stringCol)
XCTAssertEqual("A", results[2].stringCol)
realm.refresh()
XCTAssertEqual(3, allObjects.count)
XCTAssertEqual(2, results.count)
XCTAssertEqual("E", results[0].stringCol)
XCTAssertEqual("B", results[1].stringCol)
}
func testPassThreadSafeReferenceToLinkingObjects() {
let realm = try! Realm()
let dogA = SwiftDogObject(value: ["dogName": "Cookie", "age": 10])
let unaccessedDogB = SwiftDogObject(value: ["dogName": "Skipper", "age": 7])
// Ensures that a `LinkingObjects` without cached results can be handed over
try! realm.write {
realm.add(SwiftOwnerObject(value: ["name": "Andrea", "dog": dogA]))
realm.add(SwiftOwnerObject(value: ["name": "Mike", "dog": unaccessedDogB]))
}
XCTAssertEqual(1, dogA.owners.count)
XCTAssertEqual("Andrea", dogA.owners[0].name)
let ownersARef = ThreadSafeReference(to: dogA.owners)
let ownersBRef = ThreadSafeReference(to: unaccessedDogB.owners)
dispatchSyncNewThread {
let realm = try! Realm()
let ownersA = self.assertResolve(realm, ownersARef)!
let ownersB = self.assertResolve(realm, ownersBRef)!
XCTAssertEqual(1, ownersA.count)
XCTAssertEqual("Andrea", ownersA[0].name)
XCTAssertEqual(1, ownersB.count)
XCTAssertEqual("Mike", ownersB[0].name)
try! realm.write {
(ownersA[0].dog, ownersB[0].dog) = (ownersB[0].dog, ownersA[0].dog)
}
XCTAssertEqual(1, ownersA.count)
XCTAssertEqual("Mike", ownersA[0].name)
XCTAssertEqual(1, ownersB.count)
XCTAssertEqual("Andrea", ownersB[0].name)
}
XCTAssertEqual(1, dogA.owners.count)
XCTAssertEqual("Andrea", dogA.owners[0].name)
XCTAssertEqual(1, unaccessedDogB.owners.count)
XCTAssertEqual("Mike", unaccessedDogB.owners[0].name)
realm.refresh()
XCTAssertEqual(1, dogA.owners.count)
XCTAssertEqual("Mike", dogA.owners[0].name)
XCTAssertEqual(1, unaccessedDogB.owners.count)
XCTAssertEqual("Andrea", unaccessedDogB.owners[0].name)
}
func testPassThreadSafeReferenceToAnyRealmCollection() {
let realm = try! Realm()
let company = SwiftCompanyObject()
try! realm.write {
realm.add(company)
company.employees.append(SwiftEmployeeObject(value: ["name": "A"]))
company.employees.append(SwiftEmployeeObject(value: ["name": "B"]))
company.employees.append(SwiftEmployeeObject(value: ["name": "C"]))
company.employees.append(SwiftEmployeeObject(value: ["name": "D"]))
}
let results = AnyRealmCollection(realm.objects(SwiftEmployeeObject.self)
.filter("name != 'C'")
.sorted(byKeyPath: "name", ascending: false))
let list = AnyRealmCollection(company.employees)
XCTAssertEqual(3, results.count)
XCTAssertEqual("D", results[0].name)
XCTAssertEqual("B", results[1].name)
XCTAssertEqual("A", results[2].name)
XCTAssertEqual(4, list.count)
XCTAssertEqual("A", list[0].name)
XCTAssertEqual("B", list[1].name)
XCTAssertEqual("C", list[2].name)
XCTAssertEqual("D", list[3].name)
let resultsRef = ThreadSafeReference(to: results)
let listRef = ThreadSafeReference(to: list)
dispatchSyncNewThread {
let realm = try! Realm()
let results = self.assertResolve(realm, resultsRef)!
let list = self.assertResolve(realm, listRef)!
XCTAssertEqual(3, results.count)
XCTAssertEqual("D", results[0].name)
XCTAssertEqual("B", results[1].name)
XCTAssertEqual("A", results[2].name)
XCTAssertEqual(4, list.count)
XCTAssertEqual("A", list[0].name)
XCTAssertEqual("B", list[1].name)
XCTAssertEqual("C", list[2].name)
XCTAssertEqual("D", list[3].name)
}
}
}