Naming & Docs

This commit is contained in:
Quentin Jin 2019-03-19 22:54:16 +08:00
parent 3cbf95efbf
commit 34cac2aab8
11 changed files with 188 additions and 127 deletions

View File

@ -25,7 +25,7 @@
OBJ_101 /* XCTestManifests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_38 /* XCTestManifests.swift */; }; OBJ_101 /* XCTestManifests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_38 /* XCTestManifests.swift */; };
OBJ_103 /* Schedule.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "Schedule::Schedule::Product" /* Schedule.framework */; }; OBJ_103 /* Schedule.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "Schedule::Schedule::Product" /* Schedule.framework */; };
OBJ_50 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* Atomic.swift */; }; OBJ_50 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* Atomic.swift */; };
OBJ_51 /* Cabinet.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* Cabinet.swift */; }; OBJ_51 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* Bag.swift */; };
OBJ_52 /* DeinitObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* DeinitObserver.swift */; }; OBJ_52 /* DeinitObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* DeinitObserver.swift */; };
OBJ_53 /* Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* Deprecated.swift */; }; OBJ_53 /* Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* Deprecated.swift */; };
OBJ_54 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* Extensions.swift */; }; OBJ_54 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* Extensions.swift */; };
@ -44,7 +44,7 @@
OBJ_74 /* Schedule.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "Schedule::Schedule::Product" /* Schedule.framework */; }; OBJ_74 /* Schedule.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "Schedule::Schedule::Product" /* Schedule.framework */; };
OBJ_81 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; }; OBJ_81 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; };
OBJ_92 /* AtomicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* AtomicTests.swift */; }; OBJ_92 /* AtomicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* AtomicTests.swift */; };
OBJ_93 /* CabinetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* CabinetTests.swift */; }; OBJ_93 /* BagTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* BagTests.swift */; };
OBJ_94 /* DateTimeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* DateTimeTests.swift */; }; OBJ_94 /* DateTimeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* DateTimeTests.swift */; };
OBJ_95 /* DeinitObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_32 /* DeinitObserverTests.swift */; }; OBJ_95 /* DeinitObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_32 /* DeinitObserverTests.swift */; };
OBJ_96 /* ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_33 /* ExtensionsTests.swift */; }; OBJ_96 /* ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_33 /* ExtensionsTests.swift */; };
@ -78,7 +78,7 @@
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
OBJ_10 /* Cabinet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cabinet.swift; sourceTree = "<group>"; }; OBJ_10 /* Bag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bag.swift; sourceTree = "<group>"; };
OBJ_11 /* DeinitObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeinitObserver.swift; sourceTree = "<group>"; }; OBJ_11 /* DeinitObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeinitObserver.swift; sourceTree = "<group>"; };
OBJ_12 /* Deprecated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Deprecated.swift; sourceTree = "<group>"; }; OBJ_12 /* Deprecated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Deprecated.swift; sourceTree = "<group>"; };
OBJ_13 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; }; OBJ_13 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
@ -95,7 +95,7 @@
OBJ_25 /* Log.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = "<group>"; }; OBJ_25 /* Log.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = "<group>"; };
OBJ_26 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; }; OBJ_26 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
OBJ_29 /* AtomicTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicTests.swift; sourceTree = "<group>"; }; OBJ_29 /* AtomicTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicTests.swift; sourceTree = "<group>"; };
OBJ_30 /* CabinetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CabinetTests.swift; sourceTree = "<group>"; }; OBJ_30 /* BagTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BagTests.swift; sourceTree = "<group>"; };
OBJ_31 /* DateTimeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTimeTests.swift; sourceTree = "<group>"; }; OBJ_31 /* DateTimeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTimeTests.swift; sourceTree = "<group>"; };
OBJ_32 /* DeinitObserverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeinitObserverTests.swift; sourceTree = "<group>"; }; OBJ_32 /* DeinitObserverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeinitObserverTests.swift; sourceTree = "<group>"; };
OBJ_33 /* ExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionsTests.swift; sourceTree = "<group>"; }; OBJ_33 /* ExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionsTests.swift; sourceTree = "<group>"; };
@ -139,13 +139,24 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
6639192D223FD4B5000F412E /* Utils */ = {
isa = PBXGroup;
children = (
OBJ_29 /* AtomicTests.swift */,
OBJ_30 /* BagTests.swift */,
OBJ_32 /* DeinitObserverTests.swift */,
OBJ_33 /* ExtensionsTests.swift */,
);
name = Utils;
sourceTree = "<group>";
};
66C87992223A90D300A95D60 /* Utils */ = { 66C87992223A90D300A95D60 /* Utils */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
OBJ_13 /* Extensions.swift */, OBJ_13 /* Extensions.swift */,
OBJ_11 /* DeinitObserver.swift */, OBJ_11 /* DeinitObserver.swift */,
OBJ_9 /* Atomic.swift */, OBJ_9 /* Atomic.swift */,
OBJ_10 /* Cabinet.swift */, OBJ_10 /* Bag.swift */,
); );
name = Utils; name = Utils;
sourceTree = "<group>"; sourceTree = "<group>";
@ -183,11 +194,8 @@
OBJ_28 /* ScheduleTests */ = { OBJ_28 /* ScheduleTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
OBJ_29 /* AtomicTests.swift */, 6639192D223FD4B5000F412E /* Utils */,
OBJ_30 /* CabinetTests.swift */,
OBJ_31 /* DateTimeTests.swift */, OBJ_31 /* DateTimeTests.swift */,
OBJ_32 /* DeinitObserverTests.swift */,
OBJ_33 /* ExtensionsTests.swift */,
OBJ_34 /* Helpers.swift */, OBJ_34 /* Helpers.swift */,
OBJ_35 /* PlanTests.swift */, OBJ_35 /* PlanTests.swift */,
OBJ_36 /* TaskCenterTests.swift */, OBJ_36 /* TaskCenterTests.swift */,
@ -358,7 +366,7 @@
buildActionMask = 0; buildActionMask = 0;
files = ( files = (
OBJ_50 /* Atomic.swift in Sources */, OBJ_50 /* Atomic.swift in Sources */,
OBJ_51 /* Cabinet.swift in Sources */, OBJ_51 /* Bag.swift in Sources */,
OBJ_52 /* DeinitObserver.swift in Sources */, OBJ_52 /* DeinitObserver.swift in Sources */,
OBJ_53 /* Deprecated.swift in Sources */, OBJ_53 /* Deprecated.swift in Sources */,
OBJ_54 /* Extensions.swift in Sources */, OBJ_54 /* Extensions.swift in Sources */,
@ -397,7 +405,7 @@
buildActionMask = 0; buildActionMask = 0;
files = ( files = (
OBJ_92 /* AtomicTests.swift in Sources */, OBJ_92 /* AtomicTests.swift in Sources */,
OBJ_93 /* CabinetTests.swift in Sources */, OBJ_93 /* BagTests.swift in Sources */,
OBJ_94 /* DateTimeTests.swift in Sources */, OBJ_94 /* DateTimeTests.swift in Sources */,
OBJ_95 /* DeinitObserverTests.swift in Sources */, OBJ_95 /* DeinitObserverTests.swift in Sources */,
OBJ_96 /* ExtensionsTests.swift in Sources */, OBJ_96 /* ExtensionsTests.swift in Sources */,

View File

@ -1,11 +1,12 @@
import Foundation import Foundation
/// A value box that can read and write the underlying value atomically. /// Represents a box that can read and write the underlying value atomically.
final class Atomic<T> { final class Atomic<T> {
private var v: T private var v: T
private let lock = NSLock() private let lock = NSLock()
/// Init with the underlying value.
init(_ value: T) { init(_ value: T) {
self.v = value self.v = value
} }

104
Sources/Schedule/Bag.swift Normal file
View File

@ -0,0 +1,104 @@
import Foundation
/// A unique key used to remove the corresponding element from a bag.
struct BagKey: Equatable {
fileprivate let i: UInt64
fileprivate init(underlying: UInt64) {
self.i = underlying
}
/// Returns a Boolean value indicating whether two BagKeys are equal.
static func == (lhs: BagKey, rhs: BagKey) -> Bool {
return lhs.i == rhs.i
}
}
/// A generator can generate a sequence of unique `BagKey`.
///
/// let k1 = gen.next()
/// let k2 = gen.next()
/// ...
struct BagKeyGenerator: Sequence, IteratorProtocol {
typealias Element = BagKey
private var k = BagKey(underlying: 0)
/// Gets next BagKey.
mutating func next() -> Element? {
if k.i == UInt64.max {
return nil
}
defer { k = BagKey(underlying: k.i + 1) }
return k
}
}
/// A data structure used to store a sequence of elements.
///
/// let k1 = bag.append(e1)
/// let k2 = bag.append(e2)
///
/// for e in bag {
/// // -> e1
/// // -> e2
/// }
///
/// bag.delete(k1)
struct Bag<Element> {
private typealias Entry = (key: BagKey, element: Element)
private var keys = BagKeyGenerator()
private var entries: [Entry] = []
/// Pushes the given element on to the end of this container.
@discardableResult
mutating func append(_ new: Element) -> BagKey {
let key = keys.next()!
let entry = (key: key, element: new)
entries.append(entry)
return key
}
/// Returns the element for key if key is in this container.
func get(_ key: BagKey) -> Element? {
if let entry = entries.first(where: { $0.key == key }) {
return entry.element
}
return nil
}
/// Deletes the element with the given key and returns this element.
@discardableResult
mutating func delete(_ key: BagKey) -> Element? {
if let i = entries.firstIndex(where: { $0.key == key }) {
return entries.remove(at: i).element
}
return nil
}
/// Removes all elements from this containers.
mutating func clear() {
entries.removeAll()
}
/// The number of elements in this containers.
var count: Int {
return entries.count
}
}
extension Bag: Sequence {
func makeIterator() -> AnyIterator<Element> {
var iterator = entries.makeIterator()
return AnyIterator<Element> {
return iterator.next()?.element
}
}
}

View File

@ -1,70 +0,0 @@
import Foundation
struct CabinetKey: Equatable {
private let i: UInt64
init(underlying: UInt64) {
self.i = underlying
}
func increased() -> CabinetKey {
return CabinetKey(underlying: i &+ 1)
}
static func == (lhs: CabinetKey, rhs: CabinetKey) -> Bool {
return lhs.i == rhs.i
}
}
struct Cabinet<Element> {
private typealias Entry = (key: CabinetKey, element: Element)
private var key = CabinetKey(underlying: 0)
private var entries: [Entry] = []
@discardableResult
mutating func append(_ new: Element) -> CabinetKey {
defer { key = key.increased() }
let entry = (key: key, element: new)
entries.append(entry)
return key
}
func get(_ key: CabinetKey) -> Element? {
if let entry = entries.first(where: { $0.key == key }) {
return entry.element
}
return nil
}
@discardableResult
mutating func delete(_ key: CabinetKey) -> Element? {
if let i = entries.firstIndex(where: { $0.key == key }) {
return entries.remove(at: i).element
}
return nil
}
mutating func clear() {
entries.removeAll()
}
var count: Int {
return entries.count
}
}
extension Cabinet: Sequence {
func makeIterator() -> AnyIterator<Element> {
var iterator = entries.makeIterator()
return AnyIterator<Element> {
return iterator.next()?.element
}
}
}

View File

@ -1,12 +1,19 @@
import Foundation import Foundation
#if canImport(ObjectiveC) #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
private var deinitObserverKey: Void = () private var DEINIT_OBSERVER_KEY: Void = ()
/// Used to observe object deinit.
///
/// let observer = DeinitObserver.observe(target) {
/// print("\(target) deinit")
/// }
///
/// observer.cancel()
class DeinitObserver { class DeinitObserver {
private(set) weak var object: AnyObject? private(set) weak var observed: AnyObject?
private var action: (() -> Void)? private var action: (() -> Void)?
@ -14,23 +21,25 @@ class DeinitObserver {
self.action = action self.action = action
} }
/// Installs observation.
@discardableResult @discardableResult
static func observe( static func observe(
_ object: AnyObject, _ object: AnyObject,
onDeinit action: @escaping () -> Void onDeinit action: @escaping () -> Void
) -> DeinitObserver { ) -> DeinitObserver {
let observer = DeinitObserver(action) let observer = DeinitObserver(action)
observer.object = object observer.observed = object
objc_setAssociatedObject(object, &deinitObserverKey, observer, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) objc_setAssociatedObject(object, &DEINIT_OBSERVER_KEY, observer, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return observer return observer
} }
func invalidate() { /// Uninstalls observation.
func cancel() {
action = nil action = nil
if let o = object { if let o = observed {
objc_setAssociatedObject(o, &deinitObserverKey, nil, .OBJC_ASSOCIATION_ASSIGN) objc_setAssociatedObject(o, &DEINIT_OBSERVER_KEY, nil, .OBJC_ASSOCIATION_ASSIGN)
} }
} }

View File

@ -22,6 +22,7 @@ extension Int {
extension Calendar { extension Calendar {
/// The gregorian calendar with `en_US_POSIX` locale.
static let gregorian: Calendar = { static let gregorian: Calendar = {
var cal = Calendar(identifier: .gregorian) var cal = Calendar(identifier: .gregorian)
cal.locale = Locale(identifier: "en_US_POSIX") cal.locale = Locale(identifier: "en_US_POSIX")
@ -31,6 +32,7 @@ extension Calendar {
extension Date { extension Date {
/// Zero o'clock in the morning.
var startOfToday: Date { var startOfToday: Date {
return Calendar.gregorian.startOfDay(for: self) return Calendar.gregorian.startOfDay(for: self)
} }
@ -38,10 +40,17 @@ extension Date {
extension NSLocking { extension NSLocking {
/// Executes a closure returning a value while acquiring the lock.
@inline(__always) @inline(__always)
func withLock<T>(_ body: () throws -> T) rethrows -> T { func withLock<T>(_ body: () throws -> T) rethrows -> T {
lock() lock(); defer { unlock() }
defer { unlock() }
return try body() return try body()
} }
/// Executes a closure returning a value while acquiring the lock.
@inline(__always)
func withLock(_ body: () throws -> Void) rethrows {
lock(); defer { unlock() }
try body()
}
} }

View File

@ -3,19 +3,21 @@ import Foundation
/// `ActionKey` represents a token that can be used to remove the action. /// `ActionKey` represents a token that can be used to remove the action.
public struct ActionKey { public struct ActionKey {
fileprivate let cabinetKey: CabinetKey fileprivate let bagKey: BagKey
} }
extension CabinetKey { extension BagKey {
func asActionKey() -> ActionKey { fileprivate func asActionKey() -> ActionKey {
return ActionKey(cabinetKey: self) return ActionKey(bagKey: self)
} }
} }
/// `Task` represents a timed task. /// `Task` represents a timed task.
open class Task { open class Task {
public let id = UUID()
public typealias Action = (Task) -> Void public typealias Action = (Task) -> Void
private let _mutex = NSRecursiveLock() private let _mutex = NSRecursiveLock()
@ -23,8 +25,8 @@ open class Task {
private var _iterator: AnyIterator<Interval> private var _iterator: AnyIterator<Interval>
private var _timer: DispatchSourceTimer private var _timer: DispatchSourceTimer
private lazy var _onElapseActions = Cabinet<Action>() private lazy var _onElapseActions = Bag<Action>()
private lazy var _onDeinitActions = Cabinet<Action>() private lazy var _onDeinitActions = Bag<Action>()
private lazy var _suspensions: UInt64 = 0 private lazy var _suspensions: UInt64 = 0
private lazy var _timeline = Timeline() private lazy var _timeline = Timeline()
@ -34,8 +36,8 @@ open class Task {
private lazy var _lifetime: Interval = Int.max.seconds private lazy var _lifetime: Interval = Int.max.seconds
private lazy var _lifetimeTimer: DispatchSourceTimer = { private lazy var _lifetimeTimer: DispatchSourceTimer = {
let timer = DispatchSource.makeTimerSource() let timer = DispatchSource.makeTimerSource()
timer.setEventHandler { timer.setEventHandler { [weak self] in
self.cancel() self?.cancel()
} }
timer.schedule(after: _lifetime) timer.schedule(after: _lifetime)
timer.resume() timer.resume()
@ -100,7 +102,7 @@ open class Task {
/// Execute this task now, without disrupting its plan. /// Execute this task now, without disrupting its plan.
public func execute() { public func execute() {
let actions = _mutex.withLock { () -> Cabinet<Task.Action> in let actions = _mutex.withLock { () -> Bag<Task.Action> in
let now = Date() let now = Date()
if _timeline.firstExecution == nil { if _timeline.firstExecution == nil {
_timeline.firstExecution = now _timeline.firstExecution = now
@ -117,7 +119,7 @@ open class Task {
execute() execute()
} }
#if canImport(ObjectiveC) #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
open func host(on target: AnyObject) { open func host(on target: AnyObject) {
DeinitObserver.observe(target) { [weak self] in DeinitObserver.observe(target) { [weak self] in
self?.cancel() self?.cancel()
@ -287,7 +289,7 @@ open class Task {
/// Removes action by key from this task. /// Removes action by key from this task.
public func removeAction(byKey key: ActionKey) { public func removeAction(byKey key: ActionKey) {
_mutex.withLock { _mutex.withLock {
_ = _onElapseActions.delete(key.cabinetKey) _ = _onElapseActions.delete(key.bagKey)
} }
} }
@ -306,9 +308,8 @@ open class Task {
extension Task: Hashable { extension Task: Hashable {
public func hash(into hasher: inout Hasher) { public func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(self)) hasher.combine(id)
} }
/// Returns a boolean value indicating whether two tasks are equal. /// Returns a boolean value indicating whether two tasks are equal.

View File

@ -22,13 +22,13 @@ extension Timeline: CustomStringConvertible {
/// A textual representation of this timeline. /// A textual representation of this timeline.
public var description: String { public var description: String {
enum Cache { enum Lazy {
static let fmt = ISO8601DateFormatter() static let fmt = ISO8601DateFormatter()
} }
let desc = { (d: Date?) -> String in let desc = { (d: Date?) -> String in
guard let d = d else { return "nil" } guard let d = d else { return "nil" }
return Cache.fmt.string(from: d) return Lazy.fmt.string(from: d)
} }
return "Timeline: { " + return "Timeline: { " +

View File

@ -1,26 +1,29 @@
import XCTest import XCTest
@testable import Schedule @testable import Schedule
final class CabinetTests: XCTestCase { final class BagTests: XCTestCase {
typealias Fn = () -> Int typealias Fn = () -> Int
func testCabinetKey() { func testBagKey() {
let key = CabinetKey(underlying: 0) var g = BagKeyGenerator()
XCTAssertEqual(key.increased(), CabinetKey(underlying: 1)) let k1 = g.next()
let k2 = g.next()
XCTAssertNotNil(k1)
XCTAssertNotNil(k2)
XCTAssertNotEqual(k1, k2)
} }
func testAppend() { func testAppend() {
var cabinet = Cabinet<Fn>() var cabinet = Bag<Fn>()
let k1 = cabinet.append { 1 } cabinet.append { 1 }
let k2 = cabinet.append { 2 } cabinet.append { 2 }
XCTAssertEqual(k1.increased(), k2)
XCTAssertEqual(cabinet.count, 2) XCTAssertEqual(cabinet.count, 2)
} }
func testGet() { func testGet() {
var cabinet = Cabinet<Fn>() var cabinet = Bag<Fn>()
let k1 = cabinet.append { 1 } let k1 = cabinet.append { 1 }
let k2 = cabinet.append { 2 } let k2 = cabinet.append { 2 }
@ -33,12 +36,10 @@ final class CabinetTests: XCTestCase {
} }
XCTAssertEqual(fn1(), 1) XCTAssertEqual(fn1(), 1)
XCTAssertEqual(fn2(), 2) XCTAssertEqual(fn2(), 2)
XCTAssertNil(cabinet.get(k2.increased()))
} }
func testDelete() { func testDelete() {
var cabinet = Cabinet<Fn>() var cabinet = Bag<Fn>()
let k1 = cabinet.append { 1 } let k1 = cabinet.append { 1 }
let k2 = cabinet.append { 2 } let k2 = cabinet.append { 2 }
@ -52,12 +53,10 @@ final class CabinetTests: XCTestCase {
XCTAssertNotNil(fn2) XCTAssertNotNil(fn2)
XCTAssertEqual(cabinet.count, 0) XCTAssertEqual(cabinet.count, 0)
XCTAssertNil(cabinet.delete(k2.increased()))
} }
func testClear() { func testClear() {
var cabinet = Cabinet<Fn>() var cabinet = Bag<Fn>()
cabinet.append { 1 } cabinet.append { 1 }
cabinet.append { 2 } cabinet.append { 2 }
@ -69,7 +68,7 @@ final class CabinetTests: XCTestCase {
} }
func testSequence() { func testSequence() {
var cabinet = Cabinet<Fn>() var cabinet = Bag<Fn>()
cabinet.append { 0 } cabinet.append { 0 }
cabinet.append { 1 } cabinet.append { 1 }
cabinet.append { 2 } cabinet.append { 2 }
@ -82,7 +81,7 @@ final class CabinetTests: XCTestCase {
} }
static var allTests = [ static var allTests = [
("testCabinetKey", testCabinetKey), ("testBagKey", testBagKey),
("testAppend", testAppend), ("testAppend", testAppend),
("testGet", testGet), ("testGet", testGet),
("testDelete", testDelete), ("testDelete", testDelete),

View File

@ -1,7 +1,7 @@
import XCTest import XCTest
@testable import Schedule @testable import Schedule
#if canImport(ObjectiveC) #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
final class DeinitObserverTests: XCTestCase { final class DeinitObserverTests: XCTestCase {
@ -21,7 +21,7 @@ final class DeinitObserverTests: XCTestCase {
let observer = DeinitObserver.observe(obj) { let observer = DeinitObserver.observe(obj) {
i += 1 i += 1
} }
observer.invalidate() observer.cancel()
} }
fn() fn()
XCTAssertEqual(i, 1) XCTAssertEqual(i, 1)

View File

@ -8,7 +8,7 @@ public func allTests() -> [XCTestCaseEntry] {
testCase(TaskCenterTests.allTests), testCase(TaskCenterTests.allTests),
testCase(TaskTests.allTests), testCase(TaskTests.allTests),
testCase(AtomicTests.allTests), testCase(AtomicTests.allTests),
testCase(CabinetTests.allTests), testCase(BagTests.allTests),
testCase(CalendarTests.allTests), testCase(CalendarTests.allTests),
testCase(ExtensionsTests.allTests) testCase(ExtensionsTests.allTests)
] ]