//////////////////////////////////////////////////////////////////////////// // // Copyright 2017 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. // //////////////////////////////////////////////////////////////////////////// // swiftlint:disable type_name identifier_name cyclomatic_complexity import XCTest import RealmSwift protocol ObjectFactory { static func isManaged() -> Bool } final class ManagedObjectFactory: ObjectFactory { static func isManaged() -> Bool { return true } } final class UnmanagedObjectFactory: ObjectFactory { static func isManaged() -> Bool { return false } } protocol ValueFactory { associatedtype T: RealmCollectionValue associatedtype W: RealmCollectionValue = T static func array(_ obj: SwiftListObject) -> List static func values() -> [T] } final class IntFactory: ValueFactory { static func array(_ obj: SwiftListObject) -> List { return obj.int } static func values() -> [Int] { return [1, 2, 3] } } final class Int8Factory: ValueFactory { static func array(_ obj: SwiftListObject) -> List { return obj.int8 } static func values() -> [Int8] { return [1, 2, 3] } } final class Int16Factory: ValueFactory { static func array(_ obj: SwiftListObject) -> List { return obj.int16 } static func values() -> [Int16] { return [1, 2, 3] } } final class Int32Factory: ValueFactory { static func array(_ obj: SwiftListObject) -> List { return obj.int32 } static func values() -> [Int32] { return [1, 2, 3] } } final class Int64Factory: ValueFactory { static func array(_ obj: SwiftListObject) -> List { return obj.int64 } static func values() -> [Int64] { return [1, 2, 3] } } final class FloatFactory: ValueFactory { static func array(_ obj: SwiftListObject) -> List { return obj.float } static func values() -> [Float] { return [1.1, 2.2, 3.3] } } final class DoubleFactory: ValueFactory { static func array(_ obj: SwiftListObject) -> List { return obj.double } static func values() -> [Double] { return [1.1, 2.2, 3.3] } } final class StringFactory: ValueFactory { static func array(_ obj: SwiftListObject) -> List { return obj.string } static func values() -> [String] { return ["a", "b", "c"] } } final class DataFactory: ValueFactory { static func array(_ obj: SwiftListObject) -> List { return obj.data } static func values() -> [Data] { return ["a".data(using: .utf8)!, "b".data(using: .utf8)!, "c".data(using: .utf8)!] } } final class DateFactory: ValueFactory { static func array(_ obj: SwiftListObject) -> List { return obj.date } static func values() -> [Date] { return [Date(), Date().addingTimeInterval(10), Date().addingTimeInterval(20)] } } final class OptionalIntFactory: ValueFactory { typealias W = Int static func array(_ obj: SwiftListObject) -> List { return obj.intOpt } static func values() -> [Int?] { return [nil, 1, 3] } } final class OptionalInt8Factory: ValueFactory { typealias W = Int8 static func array(_ obj: SwiftListObject) -> List { return obj.int8Opt } static func values() -> [Int8?] { return [nil, 1, 3] } } final class OptionalInt16Factory: ValueFactory { typealias W = Int16 static func array(_ obj: SwiftListObject) -> List { return obj.int16Opt } static func values() -> [Int16?] { return [nil, 1, 3] } } final class OptionalInt32Factory: ValueFactory { typealias W = Int32 static func array(_ obj: SwiftListObject) -> List { return obj.int32Opt } static func values() -> [Int32?] { return [nil, 1, 3] } } final class OptionalInt64Factory: ValueFactory { typealias W = Int64 static func array(_ obj: SwiftListObject) -> List { return obj.int64Opt } static func values() -> [Int64?] { return [nil, 1, 3] } } final class OptionalFloatFactory: ValueFactory { typealias W = Float static func array(_ obj: SwiftListObject) -> List { return obj.floatOpt } static func values() -> [Float?] { return [nil, 1.1, 3.3] } } final class OptionalDoubleFactory: ValueFactory { typealias W = Double static func array(_ obj: SwiftListObject) -> List { return obj.doubleOpt } static func values() -> [Double?] { return [nil, 1.1, 3.3] } } final class OptionalStringFactory: ValueFactory { typealias W = String static func array(_ obj: SwiftListObject) -> List { return obj.stringOpt } static func values() -> [String?] { return [nil, "a", "c"] } } final class OptionalDataFactory: ValueFactory { typealias W = Data static func array(_ obj: SwiftListObject) -> List { return obj.dataOpt } static func values() -> [Data?] { return [nil, "a".data(using: .utf8), "c".data(using: .utf8)] } } final class OptionalDateFactory: ValueFactory { typealias W = Date static func array(_ obj: SwiftListObject) -> List { return obj.dateOpt } static func values() -> [Date?] { return [nil, Date(), Date().addingTimeInterval(20)] } } class EquatableTestCase: TestCase { func assertEqualTo(_ expected: T, _ actual: T, fileName: StaticString = #file, lineNumber: UInt = #line) { XCTAssertEqual(expected, actual, file: fileName, line: lineNumber) } } class PrimitiveListTestsBase: EquatableTestCase { var realm: Realm? var obj: SwiftListObject! var array: List! var values: [V.T]! #if swift(>=4) class func _defaultTestSuite() -> XCTestSuite { return defaultTestSuite } #else class func _defaultTestSuite() -> XCTestSuite { return defaultTestSuite() } #endif override func setUp() { obj = SwiftListObject() if O.isManaged() { let config = Realm.Configuration(inMemoryIdentifier: "test", objectTypes: [SwiftListObject.self]) realm = try! Realm(configuration: config) realm!.beginWrite() realm!.add(obj) } array = V.array(obj) values = V.values() } override func tearDown() { realm?.cancelWrite() realm = nil array = nil obj = nil } } class PrimitiveListTests: PrimitiveListTestsBase { func testInvalidated() { XCTAssertFalse(array.isInvalidated) if let realm = obj.realm { realm.delete(obj) XCTAssertTrue(array.isInvalidated) } } func testIndexOf() { XCTAssertNil(array.index(of: values[0])) array.append(values[0]) assertEqualTo(0, array.index(of: values[0])) array.append(values[1]) assertEqualTo(0, array.index(of: values[0])) assertEqualTo(1, array.index(of: values[1])) } // FIXME: Not yet implemented func disabled_testIndexMatching() { XCTAssertNil(array.index(matching: "self = %@", values[0])) array.append(values[0]) assertEqualTo(0, array.index(matching: "self = %@", values[0])) array.append(values[1]) assertEqualTo(0, array.index(matching: "self = %@", values[0])) assertEqualTo(1, array.index(matching: "self = %@", values[1])) } func testSubscript() { array.append(objectsIn: values) for i in 0..: PrimitiveListTestsBase where V.T: MinMaxType { func testMin() { XCTAssertNil(array.min()) array.append(objectsIn: values.reversed()) assertEqualTo(array.min(), values.first) } func testMax() { XCTAssertNil(array.max()) array.append(objectsIn: values.reversed()) assertEqualTo(array.max(), values.last) } } class OptionalMinMaxPrimitiveListTests: PrimitiveListTestsBase where V.W: MinMaxType { // V.T and V.W? are the same thing, but the type system doesn't know that // and the protocol constraint is on V.W var array2: List { return unsafeDowncast(array!, to: List.self) } func testMin() { XCTAssertNil(array2.min()) array.append(objectsIn: values.reversed()) let expected = values[1] as! V.W assertEqualTo(array2.min(), expected) } func testMax() { XCTAssertNil(array2.max()) array.append(objectsIn: values.reversed()) let expected = values[2] as! V.W assertEqualTo(array2.max(), expected) } } class AddablePrimitiveListTests: PrimitiveListTestsBase where V.T: AddableType { func testSum() { assertEqualTo(array.sum(), V.T()) array.append(objectsIn: values) // Expressing "can be added and converted to a floating point type" as // a protocol requirement is awful, so sidestep it all with obj-c let expected = ((values.map(dynamicBridgeCast) as NSArray).value(forKeyPath: "@sum.self")! as! NSNumber).doubleValue let actual: V.T = array.sum() XCTAssertEqual((dynamicBridgeCast(fromSwift: actual) as! NSNumber).doubleValue, expected, accuracy: 0.01) } func testAverage() { XCTAssertNil(array.average()) array.append(objectsIn: values) let expected = ((values.map(dynamicBridgeCast) as NSArray).value(forKeyPath: "@avg.self")! as! NSNumber).doubleValue XCTAssertEqual(array.average()!, expected, accuracy: 0.01) } } class OptionalAddablePrimitiveListTests: PrimitiveListTestsBase where V.W: AddableType { // V.T and V.W? are the same thing, but the type system doesn't know that // and the protocol constraint is on V.W var array2: List { return unsafeDowncast(array!, to: List.self) } func testSum() { assertEqualTo(array2.sum(), V.W()) array.append(objectsIn: values) var nonNil = values! nonNil.remove(at: 0) // Expressing "can be added and converted to a floating point type" as // a protocol requirement is awful, so sidestep it all with obj-c let expected = ((nonNil.map(dynamicBridgeCast) as NSArray).value(forKeyPath: "@sum.self")! as! NSNumber).doubleValue let actual: V.W = array2.sum() XCTAssertEqual((dynamicBridgeCast(fromSwift: actual) as! NSNumber).doubleValue, expected, accuracy: 0.01) } func testAverage() { XCTAssertNil(array2.average()) array.append(objectsIn: values) var nonNil = values! nonNil.remove(at: 0) let expected = ((nonNil.map(dynamicBridgeCast) as NSArray).value(forKeyPath: "@avg.self")! as! NSNumber).doubleValue XCTAssertEqual(array2.average()!, expected, accuracy: 0.01) } } class SortablePrimitiveListTests: PrimitiveListTestsBase where V.T: Comparable { func testSorted() { var shuffled = values! shuffled.removeFirst() shuffled.append(values!.first!) array.append(objectsIn: shuffled) assertEqual(Array(array.sorted(ascending: true)), values) assertEqual(Array(array.sorted(ascending: false)), values.reversed()) } } class OptionalSortablePrimitiveListTests: PrimitiveListTestsBase where V.W: Comparable { func testSorted() { var shuffled = values! shuffled.removeFirst() shuffled.append(values!.first!) array.append(objectsIn: shuffled) let array2 = unsafeDowncast(array!, to: List.self) let values2 = unsafeBitCast(values!, to: Array.self) assertEqual(Array(array2.sorted(ascending: true)), values2) assertEqual(Array(array2.sorted(ascending: false)), values2.reversed()) } } func addTests(_ suite: XCTestSuite, _ type: OF.Type) { _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = MinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = MinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = MinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = MinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = MinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = MinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = MinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = MinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = AddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = AddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = AddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = AddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = AddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = AddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = AddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = PrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalMinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalMinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalMinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalMinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalMinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalMinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalMinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalMinMaxPrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalAddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalAddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalAddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalAddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalAddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalAddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalAddablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) } class UnmanagedPrimitiveListTests: TestCase { class func _defaultTestSuite() -> XCTestSuite { let suite = XCTestSuite(name: "Unmanaged Primitive Lists") addTests(suite, UnmanagedObjectFactory.self) return suite } #if swift(>=4) override class var defaultTestSuite: XCTestSuite { return _defaultTestSuite() } #else override class func defaultTestSuite() -> XCTestSuite { return _defaultTestSuite() } #endif } class ManagedPrimitiveListTests: TestCase { class func _defaultTestSuite() -> XCTestSuite { let suite = XCTestSuite(name: "Managed Primitive Lists") addTests(suite, ManagedObjectFactory.self) _ = SortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = SortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = SortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = SortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = SortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = SortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = SortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = SortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = SortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalSortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalSortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalSortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalSortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalSortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalSortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalSortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalSortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) _ = OptionalSortablePrimitiveListTests._defaultTestSuite().tests.map(suite.addTest) return suite } #if swift(>=4) override class var defaultTestSuite: XCTestSuite { return _defaultTestSuite() } #else override class func defaultTestSuite() -> XCTestSuite { return _defaultTestSuite() } #endif }