blob: 39f1a2eb463af31ba21005f4690b9a3f450f17df [file] [log] [blame]
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
#if !DARWIN_COMPATIBILITY_TESTS
struct IntSortable {
var value: Int
}
struct StringSortable {
var value: String
}
struct PlayerRecordSortable: Hashable {
var name: String
var victories: Int
var tiebreakerPoints: Int
}
class TestNSSortDescriptor: XCTestCase {
// Conceptually, requires a < firstCopyOfB, firstCopyOfB == secondCopyOfB, firstCopyOfB !== secondCopyOfB (if reference types)
private func assertObjectsPass<Root, Value: Comparable>(_ a: Root, _ firstCopyOfB: Root, _ secondCopyOfB: Root, keyPath: KeyPath<Root, Value>) {
do {
let sort = NSSortDescriptor(keyPath: keyPath, ascending: true)
XCTAssertEqual(sort.compare(a, to: firstCopyOfB), .orderedAscending)
XCTAssertEqual(sort.compare(firstCopyOfB, to: a), .orderedDescending)
XCTAssertEqual(sort.compare(a, to: secondCopyOfB), .orderedAscending)
XCTAssertEqual(sort.compare(secondCopyOfB, to: a), .orderedDescending)
XCTAssertEqual(sort.compare(firstCopyOfB, to: secondCopyOfB), .orderedSame)
XCTAssertEqual(sort.compare(secondCopyOfB, to: firstCopyOfB), .orderedSame)
}
do {
let sort = NSSortDescriptor(keyPath: keyPath, ascending: false)
XCTAssertEqual(sort.compare(a, to: firstCopyOfB), .orderedDescending)
XCTAssertEqual(sort.compare(firstCopyOfB, to: a), .orderedAscending)
XCTAssertEqual(sort.compare(a, to: secondCopyOfB), .orderedDescending)
XCTAssertEqual(sort.compare(secondCopyOfB, to: a), .orderedAscending)
XCTAssertEqual(sort.compare(firstCopyOfB, to: secondCopyOfB), .orderedSame)
XCTAssertEqual(sort.compare(secondCopyOfB, to: firstCopyOfB), .orderedSame)
}
}
func assertObjectsPass<Root, BridgedRoot, BaseType, Value: Comparable>(_ a: Root, _ firstCopyOfB: Root, _ secondCopyOfB: Root, _ bridgedA: BridgedRoot, _ firstCopyOfBridgedB: BridgedRoot, _ secondCopyOfBridgedB: BridgedRoot, keyPath: KeyPath<BaseType, Value>) {
do {
let sort = NSSortDescriptor(keyPath: keyPath, ascending: true)
XCTAssertEqual(sort.compare(bridgedA, to: firstCopyOfB), .orderedAscending)
XCTAssertEqual(sort.compare(a, to: firstCopyOfBridgedB), .orderedAscending)
XCTAssertEqual(sort.compare(firstCopyOfBridgedB, to: a), .orderedDescending)
XCTAssertEqual(sort.compare(firstCopyOfB, to: bridgedA), .orderedDescending)
XCTAssertEqual(sort.compare(bridgedA, to: secondCopyOfB), .orderedAscending)
XCTAssertEqual(sort.compare(a, to: secondCopyOfBridgedB), .orderedAscending)
XCTAssertEqual(sort.compare(secondCopyOfBridgedB, to: a), .orderedDescending)
XCTAssertEqual(sort.compare(secondCopyOfB, to: bridgedA), .orderedDescending)
XCTAssertEqual(sort.compare(firstCopyOfBridgedB, to: secondCopyOfB), .orderedSame)
XCTAssertEqual(sort.compare(firstCopyOfB, to: secondCopyOfBridgedB), .orderedSame)
XCTAssertEqual(sort.compare(secondCopyOfBridgedB, to: firstCopyOfB), .orderedSame)
XCTAssertEqual(sort.compare(secondCopyOfB, to: firstCopyOfBridgedB), .orderedSame)
}
do {
let sort = NSSortDescriptor(keyPath: keyPath, ascending: false)
XCTAssertEqual(sort.compare(bridgedA, to: firstCopyOfB), .orderedDescending)
XCTAssertEqual(sort.compare(a, to: firstCopyOfBridgedB), .orderedDescending)
XCTAssertEqual(sort.compare(firstCopyOfBridgedB, to: a), .orderedAscending)
XCTAssertEqual(sort.compare(firstCopyOfB, to: bridgedA), .orderedAscending)
XCTAssertEqual(sort.compare(bridgedA, to: secondCopyOfB), .orderedDescending)
XCTAssertEqual(sort.compare(a, to: secondCopyOfBridgedB), .orderedDescending)
XCTAssertEqual(sort.compare(secondCopyOfBridgedB, to: a), .orderedAscending)
XCTAssertEqual(sort.compare(secondCopyOfB, to: bridgedA), .orderedAscending)
XCTAssertEqual(sort.compare(firstCopyOfBridgedB, to: secondCopyOfB), .orderedSame)
XCTAssertEqual(sort.compare(firstCopyOfB, to: secondCopyOfBridgedB), .orderedSame)
XCTAssertEqual(sort.compare(secondCopyOfBridgedB, to: firstCopyOfB), .orderedSame)
XCTAssertEqual(sort.compare(secondCopyOfB, to: firstCopyOfBridgedB), .orderedSame)
}
}
private func assertObjectsPass<Root, Value>(_ a: Root, _ firstCopyOfB: Root, _ secondCopyOfB: Root, keyPath: KeyPath<Root, Value>, comparator: @escaping Comparator) {
do {
let sort = NSSortDescriptor(keyPath: keyPath, ascending: true, comparator: comparator)
XCTAssertEqual(sort.compare(a, to: firstCopyOfB), .orderedAscending)
XCTAssertEqual(sort.compare(firstCopyOfB, to: a), .orderedDescending)
XCTAssertEqual(sort.compare(a, to: secondCopyOfB), .orderedAscending)
XCTAssertEqual(sort.compare(secondCopyOfB, to: a), .orderedDescending)
XCTAssertEqual(sort.compare(firstCopyOfB, to: secondCopyOfB), .orderedSame)
XCTAssertEqual(sort.compare(secondCopyOfB, to: firstCopyOfB), .orderedSame)
}
do {
let sort = NSSortDescriptor(keyPath: keyPath, ascending: false, comparator: comparator)
XCTAssertEqual(sort.compare(a, to: firstCopyOfB), .orderedDescending)
XCTAssertEqual(sort.compare(firstCopyOfB, to: a), .orderedAscending)
XCTAssertEqual(sort.compare(a, to: secondCopyOfB), .orderedDescending)
XCTAssertEqual(sort.compare(secondCopyOfB, to: a), .orderedAscending)
XCTAssertEqual(sort.compare(firstCopyOfB, to: secondCopyOfB), .orderedSame)
XCTAssertEqual(sort.compare(secondCopyOfB, to: firstCopyOfB), .orderedSame)
}
}
func testComparable() {
let a = IntSortable(value: 42)
let b = IntSortable(value: 108)
let bAgain = IntSortable(value: 108)
assertObjectsPass(a, b, bAgain, keyPath: \IntSortable.value)
}
func testBuiltinComparableObject() {
let a = NSString(string: "A")
let b = NSString(string: "B")
let bAgain = NSString(string: "B")
assertObjectsPass(a, b, bAgain, keyPath: \NSString.self)
}
func testBuiltinComparableBridgeable() {
let a = NSString(string: "A")
let b = NSString(string: "B")
let bAgain = NSString(string: "B")
let aString = "A"
let bString = "B"
let bStringAgain = "B"
assertObjectsPass(a, b, bAgain, aString, bString, bStringAgain, keyPath: \NSString.self)
assertObjectsPass(a, b, bAgain, aString, bString, bStringAgain, keyPath: \String.self)
}
func testComparatorSorting() {
let canonicalOrder = [ "Velma", "Daphne", "Scooby" ]
let a = StringSortable(value: "Velma")
let b = StringSortable(value: "Daphne")
let bAgain = StringSortable(value: "Daphne")
assertObjectsPass(a, b, bAgain, keyPath: \StringSortable.value) { (lhs, rhs) -> ComparisonResult in
let lhsIndex = canonicalOrder.firstIndex(of: lhs as! String)!
let rhsIndex = canonicalOrder.firstIndex(of: rhs as! String)!
if lhsIndex < rhsIndex {
return .orderedAscending
} else if lhsIndex > rhsIndex {
return .orderedDescending
} else {
return .orderedSame
}
}
}
private let runOnlySinglePermutation = false // Useful for debugging. Always keep set to false when committing.
func permute<T>(_ array: [T]) -> [[T]] {
guard !runOnlySinglePermutation else {
return [array]
}
guard !array.isEmpty else { return [[]] }
var rest = array
let head = rest.popLast()!
let subpermutations = permute(rest)
var result: [[T]] = []
for permutation in subpermutations {
for i in 0 ..< array.count {
var edited = permutation
edited.insert(head, at: i)
result.append(edited)
}
}
return result
}
func testSortingContainers() {
let a = PlayerRecordSortable(name: "A", victories: 3, tiebreakerPoints: 0)
let b = PlayerRecordSortable(name: "B", victories: 1, tiebreakerPoints: 10)
let c = PlayerRecordSortable(name: "C", victories: 1, tiebreakerPoints: 10)
let d = PlayerRecordSortable(name: "D", victories: 1, tiebreakerPoints: 15)
func check(_ result: [Any]) {
let actualResult = result as! [PlayerRecordSortable]
XCTAssertEqual(actualResult[0].name, "A")
XCTAssertEqual(actualResult[1].name, "D")
if actualResult[2].name == "B" {
XCTAssertEqual(actualResult[2].name, "B")
XCTAssertEqual(actualResult[3].name, "C")
} else {
XCTAssertEqual(actualResult[2].name, "C")
XCTAssertEqual(actualResult[3].name, "B")
}
}
let descriptors = [
NSSortDescriptor(keyPath: \PlayerRecordSortable.victories, ascending: false),
NSSortDescriptor(keyPath: \PlayerRecordSortable.tiebreakerPoints, ascending: false),
]
let permutations = permute([a, b, c, d])
for permutation in permutations {
check(NSArray(array: permutation).sortedArray(using: descriptors))
let mutable = NSMutableArray(array: permutation)
mutable.sort(using: descriptors)
check(mutable as! [PlayerRecordSortable])
let set = NSSet(array: permutation)
check(set.sortedArray(using: descriptors))
let orderedSet = NSOrderedSet(array: permutation)
check(orderedSet.sortedArray(using: descriptors))
let mutableOrderedSet = orderedSet.mutableCopy() as! NSMutableOrderedSet
mutableOrderedSet.sort(using: descriptors)
check(mutableOrderedSet.array)
}
}
static var allTests: [(String, (TestNSSortDescriptor) -> () throws -> Void)] {
return [
("testComparable", testComparable),
("testBuiltinComparableObject", testBuiltinComparableObject),
("testBuiltinComparableBridgeable", testBuiltinComparableBridgeable),
("testComparatorSorting", testComparatorSorting),
("testSortingContainers", testSortingContainers),
]
}
}
#endif