.passUnretained(monitor).toOpaque()
68 | } else {
69 | info = nil
70 | }
71 |
72 | callout(handle, flags, info)
73 | }
74 |
75 | private var callout: SCNetworkReachabilityCallBack?
76 | private var flags: SCNetworkReachabilityFlags?
77 | private var handle: SCNetworkReachability?
78 | private weak var monitor: NetworkReachabilityMonitor?
79 | }
80 |
--------------------------------------------------------------------------------
/Tests/Mock/MockNotificationCenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockNotificationCenter.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by J. G. Pusey on 2017-12-27.
6 | //
7 | // © 2017 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import Foundation
11 | @testable import XestiMonitors
12 |
13 | internal class MockNotificationCenter: NotificationCenterProtocol {
14 | class MockObserver {
15 | let block: (Notification) -> Void
16 | let object: Any?
17 | let queue: OperationQueue?
18 |
19 | init(object: Any?,
20 | queue: OperationQueue?,
21 | block: @escaping (Notification) -> Void) {
22 | self.block = block
23 | self.object = object
24 | self.queue = queue
25 | }
26 | }
27 |
28 | var observers: [String: MockObserver] = [:]
29 |
30 | func addObserver(forName name: NSNotification.Name?,
31 | object: Any?,
32 | queue: OperationQueue?,
33 | using block: @escaping (Notification) -> Void) -> NSObjectProtocol {
34 | guard
35 | let name = name
36 | else { fatalError("Name must be specified for testing") }
37 |
38 | guard
39 | observers[name.rawValue] == nil
40 | else { fatalError("Cannot have multiple observers for same name") }
41 |
42 | observers[name.rawValue] = MockObserver(object: object,
43 | queue: queue,
44 | block: block)
45 |
46 | return name.rawValue as NSString
47 | }
48 |
49 | func post(name: NSNotification.Name,
50 | object: Any?,
51 | userInfo: [AnyHashable: Any]? = nil) {
52 | guard
53 | let observer = observers[name.rawValue]
54 | else { return }
55 |
56 | if let filter = observer.object as AnyObject? {
57 | guard
58 | let object = object as AnyObject?,
59 | filter === object
60 | else { return }
61 | }
62 |
63 | let notification = Notification(name: name,
64 | object: object,
65 | userInfo: userInfo)
66 |
67 | if let queue = observer.queue {
68 | queue.addOperation { observer.block(notification) }
69 | } else {
70 | observer.block(notification)
71 | }
72 | }
73 |
74 | func removeObserver(_ observer: Any) {
75 | guard
76 | let name = observer as? String
77 | else { return }
78 |
79 | observers[name] = nil
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Tests/Mock/MockProcessInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockProcessInfo.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by J. G. Pusey on 2018-05-13.
6 | //
7 | // © 2018 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import Foundation
11 | @testable import XestiMonitors
12 |
13 | internal class MockProcessInfo: ProcessInfoProtocol {
14 | init() {
15 | self.isLowPowerModeEnabled = false
16 | self.rawThermalState = 0
17 | }
18 |
19 | var isLowPowerModeEnabled: Bool
20 |
21 | @available(iOS 11.0, OSX 10.10.3, tvOS 11.0, watchOS 4.0, *)
22 | var thermalState: ProcessInfo.ThermalState {
23 | guard
24 | let state = ProcessInfo.ThermalState(rawValue: rawThermalState)
25 | else { return .nominal }
26 |
27 | return state
28 | }
29 |
30 | // MARK: -
31 |
32 | var rawThermalState: Int
33 | }
34 |
--------------------------------------------------------------------------------
/Tests/Mock/UIFocusUpdateContext+Neutered.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIFocusUpdateContext+Neutered.h
3 | // XestiMonitorsTests
4 | //
5 | // Created by J. G. Pusey on 2018-05-05.
6 | //
7 | // © 2018 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | @import UIKit;
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 | @interface UIFocusUpdateContext (Neutered)
15 |
16 | + (UIFocusUpdateContext *) make;
17 |
18 | @end
19 |
20 | NS_ASSUME_NONNULL_END
21 |
--------------------------------------------------------------------------------
/Tests/Mock/UIFocusUpdateContext+Neutered.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIFocusUpdateContext+Neutered.m
3 | // XestiMonitorsTests
4 | //
5 | // Created by J. G. Pusey on 2018-05-05.
6 | //
7 | // © 2018 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | @import ObjectiveC;
11 |
12 | #import "UIFocusUpdateContext+Neutered.h"
13 |
14 | //
15 | // We need to create an instance of `UIFocusUpdateContext` in order to fully
16 | // test `FocusMonitor`. We can easily create such an instance using
17 | // `UIFocusUpdateContext()` on tvOS. For whatever reason, iOS throws an
18 | // exception for that case. So we are forced to rely on this ugly hack in
19 | // Objective-C (apparently one of the few cases where Swift falls short) to
20 | // create the instance.
21 | //
22 | @implementation UIFocusUpdateContext (Neutered)
23 |
24 | + (UIFocusUpdateContext *) make {
25 | return [[UIFocusUpdateContext alloc] initNeutered];
26 | }
27 |
28 | - (instancetype) initNeutered {
29 | return [super init]; // skip the naughty bits; just initialize super
30 | }
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/Tests/Mock/XestiMonitorsTests-iOS-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "UIFocusUpdateContext+Neutered.h"
2 |
--------------------------------------------------------------------------------
/Tests/UIKit/Application/BackgroundRefreshMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BackgroundRefreshMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by J. G. Pusey on 2017-12-27.
6 | //
7 | // © 2017 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class BackgroundRefreshMonitorTests: XCTestCase {
15 | let application = MockApplication()
16 | let notificationCenter = MockNotificationCenter()
17 |
18 | override func setUp() {
19 | super.setUp()
20 |
21 | ApplicationInjector.inject = { self.application }
22 |
23 | application.backgroundRefreshStatus = .restricted
24 |
25 | NotificationCenterInjector.inject = { self.notificationCenter }
26 | }
27 |
28 | func testMonitor_statusDidChange() {
29 | let expectation = self.expectation(description: "Handler called")
30 | let expectedStatus: UIBackgroundRefreshStatus = .available
31 | var expectedEvent: BackgroundRefreshMonitor.Event?
32 | let monitor = BackgroundRefreshMonitor(queue: .main) { event in
33 | XCTAssertEqual(OperationQueue.current, .main)
34 |
35 | expectedEvent = event
36 | expectation.fulfill()
37 | }
38 |
39 | monitor.startMonitoring()
40 | simulateStatusDidChange(to: expectedStatus)
41 | waitForExpectations(timeout: 1)
42 | monitor.stopMonitoring()
43 |
44 | if let event = expectedEvent,
45 | case let .statusDidChange(status) = event {
46 | XCTAssertEqual(status, expectedStatus)
47 | } else {
48 | XCTFail("Unexpected event")
49 | }
50 | }
51 |
52 | func testStatus() {
53 | let expectedStatus: UIBackgroundRefreshStatus = .denied
54 | let monitor = BackgroundRefreshMonitor(queue: .main) { _ in
55 | XCTAssertEqual(OperationQueue.current, .main)
56 | }
57 |
58 | simulateStatusDidChange(to: expectedStatus)
59 |
60 | XCTAssertEqual(monitor.status, expectedStatus)
61 | }
62 |
63 | private func simulateStatusDidChange(to status: UIBackgroundRefreshStatus) {
64 | application.backgroundRefreshStatus = status
65 |
66 | notificationCenter.post(name: .UIApplicationBackgroundRefreshStatusDidChange,
67 | object: application)
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Tests/UIKit/Application/MemoryMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MemoryMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by J. G. Pusey on 2017-12-27.
6 | //
7 | // © 2017 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class MemoryMonitorTests: XCTestCase {
15 | let application = MockApplication()
16 | let notificationCenter = MockNotificationCenter()
17 |
18 | override func setUp() {
19 | super.setUp()
20 |
21 | ApplicationInjector.inject = { self.application }
22 |
23 | NotificationCenterInjector.inject = { self.notificationCenter }
24 | }
25 |
26 | func testMonitor_didReceiveWarning() {
27 | let expectation = self.expectation(description: "Handler called")
28 | var expectedEvent: MemoryMonitor.Event?
29 | let monitor = MemoryMonitor(queue: .main) { event in
30 | XCTAssertEqual(OperationQueue.current, .main)
31 |
32 | expectedEvent = event
33 | expectation.fulfill()
34 | }
35 |
36 | monitor.startMonitoring()
37 | simulateDidReceiveMemoryWarning()
38 | waitForExpectations(timeout: 1)
39 | monitor.stopMonitoring()
40 |
41 | if let event = expectedEvent {
42 | XCTAssertEqual(event, .didReceiveWarning)
43 | } else {
44 | XCTFail("Unexpected event")
45 | }
46 | }
47 |
48 | private func simulateDidReceiveMemoryWarning() {
49 | notificationCenter.post(name: .UIApplicationDidReceiveMemoryWarning,
50 | object: application)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Tests/UIKit/Application/ScreenshotMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenshotMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by J. G. Pusey on 2017-12-27.
6 | //
7 | // © 2017 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class ScreenshotMonitorTests: XCTestCase {
15 | let application = MockApplication()
16 | let notificationCenter = MockNotificationCenter()
17 |
18 | override func setUp() {
19 | super.setUp()
20 |
21 | ApplicationInjector.inject = { self.application }
22 |
23 | NotificationCenterInjector.inject = { self.notificationCenter }
24 | }
25 |
26 | func testMonitor_userDidTake() {
27 | let expectation = self.expectation(description: "Handler called")
28 | var expectedEvent: ScreenshotMonitor.Event?
29 | let monitor = ScreenshotMonitor(queue: .main) { event in
30 | XCTAssertEqual(OperationQueue.current, .main)
31 |
32 | expectedEvent = event
33 | expectation.fulfill()
34 | }
35 |
36 | monitor.startMonitoring()
37 | simulateUserDidTake()
38 | waitForExpectations(timeout: 1)
39 | monitor.stopMonitoring()
40 |
41 | if let event = expectedEvent {
42 | XCTAssertEqual(event, .userDidTake)
43 | } else {
44 | XCTFail("Unexpected event")
45 | }
46 | }
47 |
48 | private func simulateUserDidTake() {
49 | notificationCenter.post(name: .UIApplicationUserDidTakeScreenshot,
50 | object: application)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Tests/UIKit/Application/TimeMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TimeMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by J. G. Pusey on 2017-12-27.
6 | //
7 | // © 2017 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class TimeMonitorTests: XCTestCase {
15 | let application = MockApplication()
16 | let notificationCenter = MockNotificationCenter()
17 |
18 | override func setUp() {
19 | super.setUp()
20 |
21 | ApplicationInjector.inject = { self.application }
22 |
23 | NotificationCenterInjector.inject = { self.notificationCenter }
24 | }
25 |
26 | func testMonitor_significantChange() {
27 | let expectation = self.expectation(description: "Handler called")
28 | var expectedEvent: TimeMonitor.Event?
29 | let monitor = TimeMonitor(queue: .main) { event in
30 | XCTAssertEqual(OperationQueue.current, .main)
31 |
32 | expectedEvent = event
33 | expectation.fulfill()
34 | }
35 |
36 | monitor.startMonitoring()
37 | simulateSignificantChange()
38 | waitForExpectations(timeout: 1)
39 | monitor.stopMonitoring()
40 |
41 | if let event = expectedEvent {
42 | XCTAssertEqual(event, .significantChange)
43 | } else {
44 | XCTFail("Unexpected event")
45 | }
46 | }
47 |
48 | private func simulateSignificantChange() {
49 | notificationCenter.post(name: .UIApplicationSignificantTimeChange,
50 | object: application)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Tests/UIKit/Device/OrientationMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OrientationMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by J. G. Pusey on 2017-12-27.
6 | //
7 | // © 2017 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class OrientationMonitorTests: XCTestCase {
15 | let device = MockDevice()
16 | let notificationCenter = MockNotificationCenter()
17 |
18 | override func setUp() {
19 | super.setUp()
20 |
21 | DeviceInjector.inject = { self.device }
22 |
23 | device.orientation = .unknown
24 |
25 | NotificationCenterInjector.inject = { self.notificationCenter }
26 | }
27 |
28 | func testMonitor_didChange() {
29 | let expectation = self.expectation(description: "Handler called")
30 | let expectedOrientation: UIDeviceOrientation = .portrait
31 | var expectedEvent: OrientationMonitor.Event?
32 | let monitor = OrientationMonitor(queue: .main) { event in
33 | XCTAssertEqual(OperationQueue.current, .main)
34 |
35 | expectedEvent = event
36 | expectation.fulfill()
37 | }
38 |
39 | monitor.startMonitoring()
40 | simulateDidChange(to: expectedOrientation)
41 | waitForExpectations(timeout: 1)
42 | monitor.stopMonitoring()
43 |
44 | if let event = expectedEvent,
45 | case let .didChange(orientation) = event {
46 | XCTAssertEqual(orientation, expectedOrientation)
47 | } else {
48 | XCTFail("Unexpected event")
49 | }
50 | }
51 |
52 | func testOrientation() {
53 | let expectedOrientation: UIDeviceOrientation = .landscapeRight
54 | let monitor = OrientationMonitor(queue: .main) { _ in
55 | XCTAssertEqual(OperationQueue.current, .main)
56 | }
57 |
58 | simulateDidChange(to: expectedOrientation)
59 |
60 | XCTAssertEqual(monitor.orientation, expectedOrientation)
61 | }
62 |
63 | private func simulateDidChange(to orientation: UIDeviceOrientation) {
64 | device.orientation = orientation
65 |
66 | notificationCenter.post(name: .UIDeviceOrientationDidChange,
67 | object: device)
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Tests/UIKit/Device/ProximityMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProximityMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by J. G. Pusey on 2017-12-27.
6 | //
7 | // © 2017 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class ProximityMonitorTests: XCTestCase {
15 | let device = MockDevice()
16 | let notificationCenter = MockNotificationCenter()
17 |
18 | override func setUp() {
19 | super.setUp()
20 |
21 | DeviceInjector.inject = { self.device }
22 |
23 | device.proximityState = false
24 |
25 | NotificationCenterInjector.inject = { self.notificationCenter }
26 | }
27 |
28 | func testIsAvailable() {
29 | let monitor = ProximityMonitor(queue: .main) { _ in
30 | XCTAssertEqual(OperationQueue.current, .main)
31 | }
32 |
33 | device.isProximityMonitoringEnabled = false
34 |
35 | XCTAssertFalse(device.isProximityMonitoringEnabled)
36 | XCTAssertTrue(monitor.isAvailable)
37 | XCTAssertFalse(device.isProximityMonitoringEnabled)
38 | }
39 |
40 | func testMonitor_stateDidChange() {
41 | let expectation = self.expectation(description: "Handler called")
42 | let expectedState: Bool = true
43 | var expectedEvent: ProximityMonitor.Event?
44 | let monitor = ProximityMonitor(queue: .main) { event in
45 | XCTAssertEqual(OperationQueue.current, .main)
46 |
47 | expectedEvent = event
48 | expectation.fulfill()
49 | }
50 |
51 | monitor.startMonitoring()
52 | simulateStateDidChange(to: expectedState)
53 | waitForExpectations(timeout: 1)
54 | monitor.stopMonitoring()
55 |
56 | if let event = expectedEvent,
57 | case let .stateDidChange(state) = event {
58 | XCTAssertEqual(state, expectedState)
59 | } else {
60 | XCTFail("Unexpected event")
61 | }
62 | }
63 |
64 | func testState() {
65 | let expectedState: Bool = true
66 | let monitor = ProximityMonitor(queue: .main) { _ in
67 | XCTAssertEqual(OperationQueue.current, .main)
68 | }
69 |
70 | simulateStateDidChange(to: expectedState)
71 |
72 | XCTAssertEqual(monitor.state, expectedState)
73 | }
74 |
75 | private func simulateStateDidChange(to state: Bool) {
76 | device.proximityState = state
77 |
78 | notificationCenter.post(name: .UIDeviceProximityStateDidChange,
79 | object: device)
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Tests/UIKit/Other/DocumentStateMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DocumentStateMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by J. G. Pusey on 2018-02-16.
6 | //
7 | // © 2018 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class DocumentStateMonitorTests: XCTestCase {
15 | let document = UIDocument(fileURL: Bundle.main.bundleURL)
16 | let notificationCenter = MockNotificationCenter()
17 |
18 | override func setUp() {
19 | super.setUp()
20 |
21 | NotificationCenterInjector.inject = { self.notificationCenter }
22 | }
23 |
24 | func testMonitor_stateDidChange() {
25 | let expectation = self.expectation(description: "Handler called")
26 | var expectedEvent: DocumentStateMonitor.Event?
27 | let monitor = DocumentStateMonitor(document: document,
28 | queue: .main) { event in
29 | XCTAssertEqual(OperationQueue.current, .main)
30 |
31 | expectedEvent = event
32 | expectation.fulfill()
33 | }
34 |
35 | monitor.startMonitoring()
36 | simulateDidChange()
37 | waitForExpectations(timeout: 1)
38 | monitor.stopMonitoring()
39 |
40 | if let event = expectedEvent,
41 | case let .didChange(test) = event {
42 | XCTAssertEqual(test, document)
43 | } else {
44 | XCTFail("Unexpected event")
45 | }
46 | }
47 |
48 | private func simulateDidChange() {
49 | notificationCenter.post(name: .UIDocumentStateChanged,
50 | object: document)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Tests/UIKit/Other/TableViewSelectionMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TableViewSelectionMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by Rose Maina on 2018-04-20.
6 | //
7 | // © 2018 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class TableViewSelectionMonitorTests: XCTestCase {
15 | let notificationCenter = MockNotificationCenter()
16 | let tableView = UITableView()
17 |
18 | override func setUp() {
19 | super.setUp()
20 |
21 | NotificationCenterInjector.inject = { self.notificationCenter }
22 | }
23 |
24 | func testMonitor_didChange() {
25 | let expectation = self.expectation(description: "Hander called")
26 | var expectedEvent: TableViewSelectionMonitor.Event?
27 | let monitor = TableViewSelectionMonitor(tableView: self.tableView,
28 | queue: .main) { event in
29 | XCTAssertEqual(OperationQueue.current, .main)
30 |
31 | expectedEvent = event
32 | expectation.fulfill()
33 | }
34 |
35 | monitor.startMonitoring()
36 | simulateDidChange()
37 | waitForExpectations(timeout: 1)
38 | monitor.stopMonitoring()
39 |
40 | if let event = expectedEvent,
41 | case let .didChange(test) = event {
42 | XCTAssertEqual(test, tableView)
43 | } else {
44 | XCTFail("Unexpected Event")
45 | }
46 | }
47 |
48 | private func simulateDidChange() {
49 | notificationCenter.post(name: .UITableViewSelectionDidChange,
50 | object: tableView)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Tests/UIKit/Other/ViewControllerShowDetailTargetMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewControllerShowDetailTargetMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by J. G. Pusey on 2018-02-16.
6 | //
7 | // © 2018 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class ViewControllerShowDetailTargetMonitorTests: XCTestCase {
15 | let notificationCenter = MockNotificationCenter()
16 | let viewController = UIViewController()
17 |
18 | override func setUp() {
19 | super.setUp()
20 |
21 | NotificationCenterInjector.inject = { self.notificationCenter }
22 | }
23 |
24 | func testMonitor_stateDidChange() {
25 | let expectation = self.expectation(description: "Handler called")
26 | var expectedEvent: ViewControllerShowDetailTargetMonitor.Event?
27 | let monitor = ViewControllerShowDetailTargetMonitor(queue: .main) { event in
28 | XCTAssertEqual(OperationQueue.current, .main)
29 |
30 | expectedEvent = event
31 | expectation.fulfill()
32 | }
33 |
34 | monitor.startMonitoring()
35 | simulateDidChange()
36 | waitForExpectations(timeout: 1)
37 | monitor.stopMonitoring()
38 |
39 | if let event = expectedEvent,
40 | case let .didChange(test) = event {
41 | XCTAssertEqual(test, viewController)
42 | } else {
43 | XCTFail("Unexpected event")
44 | }
45 | }
46 |
47 | private func simulateDidChange() {
48 | notificationCenter.post(name: .UIViewControllerShowDetailTargetDidChange,
49 | object: viewController)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Tests/UIKit/Screen/ScreenBrightnessMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenBrightnessMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by Paul Nyondo on 2018-03-25.
6 | //
7 | // © 2018 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class ScreenBrightnessMonitorTests: XCTestCase {
15 | let notificationCenter = MockNotificationCenter()
16 | let screen = UIScreen()
17 |
18 | override func setUp() {
19 | super.setUp()
20 |
21 | NotificationCenterInjector.inject = { self.notificationCenter }
22 | }
23 |
24 | func testMonitor_didChange() {
25 | let expectation = self.expectation(description: "Handler called")
26 | var expectedEvent: ScreenBrightnessMonitor.Event?
27 | let monitor = ScreenBrightnessMonitor(screen: screen,
28 | queue: .main) { event in
29 | XCTAssertEqual(OperationQueue.current, .main)
30 |
31 | expectedEvent = event
32 | expectation.fulfill()
33 | }
34 |
35 | monitor.startMonitoring()
36 | simulateDidChange()
37 | waitForExpectations(timeout: 1)
38 | monitor.stopMonitoring()
39 |
40 | if let event = expectedEvent,
41 | case let .didChange(test) = event {
42 | XCTAssertEqual(test, screen)
43 | } else {
44 | XCTFail("Unexpected event")
45 | }
46 | }
47 |
48 | private func simulateDidChange() {
49 | notificationCenter.post(name: .UIScreenBrightnessDidChange,
50 | object: screen)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Tests/UIKit/Screen/ScreenCapturedMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenCapturedMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by Paul Nyondo on 2018-04-06.
6 | //
7 | // © 2018 J. G. Pusey (see LICENSE.md).
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class ScreenCapturedMonitorTests: XCTestCase {
15 | let notificationCenter = MockNotificationCenter()
16 | let screen = UIScreen()
17 |
18 | override func setUp() {
19 | super.setUp()
20 |
21 | NotificationCenterInjector.inject = { self.notificationCenter }
22 | }
23 |
24 | func testMonitor_didChange() {
25 | if #available(iOS 11.0, tvOS 11.0, *) {
26 | let expectation = self.expectation(description: "Handler called")
27 | var expectedEvent: ScreenCapturedMonitor.Event?
28 | let monitor = ScreenCapturedMonitor(screen: screen,
29 | queue: .main) { event in
30 | XCTAssertEqual(OperationQueue.current, .main)
31 |
32 | expectedEvent = event
33 | expectation.fulfill()
34 | }
35 |
36 | monitor.startMonitoring()
37 | simulateDidChange()
38 | waitForExpectations(timeout: 1)
39 | monitor.stopMonitoring()
40 |
41 | if let event = expectedEvent,
42 | case let .didChange(test) = event {
43 | XCTAssertEqual(test, screen)
44 | } else {
45 | XCTFail("Unexpected event")
46 | }
47 | }
48 | }
49 |
50 | private func simulateDidChange() {
51 | if #available(iOS 11.0, tvOS 11.0, *) {
52 | notificationCenter.post(name: .UIScreenCapturedDidChange,
53 | object: screen)
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Tests/UIKit/Screen/ScreenConnectionMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenConnectionMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by Paul Nyondo on 2018-04-04.
6 | //
7 | // © 2018 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class ScreenConnectionMonitorTest: XCTestCase {
15 | let notificationCenter = MockNotificationCenter()
16 | let screen = UIScreen()
17 |
18 | override func setUp() {
19 | super.setUp()
20 | NotificationCenterInjector.inject = { self.notificationCenter }
21 | }
22 |
23 | func testMonitor_didConnect() {
24 | let expectation = self.expectation(description: "Handler called")
25 | var expectedEvent: ScreenConnectionMonitor.Event?
26 | let monitor = ScreenConnectionMonitor(options: .didConnect,
27 | queue: .main) { event in
28 | XCTAssertEqual(OperationQueue.current, .main)
29 |
30 | expectedEvent = event
31 | expectation.fulfill()
32 | }
33 |
34 | monitor.startMonitoring()
35 | simulateDidConnect()
36 | waitForExpectations(timeout: 1)
37 | monitor.stopMonitoring()
38 |
39 | if let event = expectedEvent,
40 | case let .didConnect(test) = event {
41 | XCTAssertEqual(test, screen)
42 | } else {
43 | XCTFail("Unexpected event")
44 | }
45 | }
46 |
47 | func testMonitor_didDisconnect() {
48 | let expectation = self.expectation(description: "Handler called")
49 | var expectedEvent: ScreenConnectionMonitor.Event?
50 | let monitor = ScreenConnectionMonitor(options: .didDisconnect,
51 | queue: .main) { event in
52 | XCTAssertEqual(OperationQueue.current, .main)
53 |
54 | expectedEvent = event
55 | expectation.fulfill()
56 | }
57 |
58 | monitor.startMonitoring()
59 | simulateDidDisconnect()
60 | waitForExpectations(timeout: 1)
61 | monitor.stopMonitoring()
62 |
63 | if let event = expectedEvent,
64 | case let .didDisconnect(test) = event {
65 | XCTAssertEqual(test, screen)
66 | } else {
67 | XCTFail("Unexpected event")
68 | }
69 | }
70 |
71 | private func simulateDidConnect() {
72 | notificationCenter.post(name: .UIScreenDidConnect,
73 | object: screen)
74 | }
75 |
76 | private func simulateDidDisconnect() {
77 | notificationCenter.post(name: .UIScreenDidDisconnect,
78 | object: screen)
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Tests/UIKit/Screen/ScreenModeMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenModeMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by Paul Nyondo on 2018-03-31.
6 | //
7 | // © 2018 J. G. Pusey (see LICENSE.md).
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class ScreenModeMonitorTests: XCTestCase {
15 | let notificationCenter = MockNotificationCenter()
16 | let screen = UIScreen()
17 |
18 | override func setUp() {
19 | super.setUp()
20 |
21 | NotificationCenterInjector.inject = { self.notificationCenter }
22 | }
23 |
24 | func testMonitor_didChange() {
25 | let expectation = self.expectation(description: "Handler called")
26 | var expectedEvent: ScreenModeMonitor.Event?
27 | let monitor = ScreenModeMonitor(screen: screen,
28 | queue: .main) { event in
29 | XCTAssertEqual(OperationQueue.current, .main)
30 |
31 | expectedEvent = event
32 | expectation.fulfill()
33 | }
34 |
35 | monitor.startMonitoring()
36 | simulateDidChange()
37 | waitForExpectations(timeout: 1)
38 | monitor.stopMonitoring()
39 |
40 | if let event = expectedEvent,
41 | case let .didChange(test) = event {
42 | XCTAssertEqual(test, screen)
43 | } else {
44 | XCTFail("Unexpected event")
45 | }
46 | }
47 |
48 | private func simulateDidChange() {
49 | notificationCenter.post(name: .UIScreenModeDidChange,
50 | object: screen)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Tests/UIKit/Text/TextInputModeMonitorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TextInputModeMonitorTests.swift
3 | // XestiMonitorsTests
4 | //
5 | // Created by J. G. Pusey on 2018-04-07.
6 | //
7 | // © 2018 J. G. Pusey (see LICENSE.md)
8 | //
9 |
10 | import UIKit
11 | import XCTest
12 | @testable import XestiMonitors
13 |
14 | internal class TextInputModeMonitorTests: XCTestCase {
15 | let notificationCenter = MockNotificationCenter()
16 | let textInputMode = UITextInputMode()
17 |
18 | override func setUp() {
19 | super.setUp()
20 |
21 | NotificationCenterInjector.inject = { self.notificationCenter }
22 | }
23 |
24 | func testMonitor_didChange() {
25 | let expectation = self.expectation(description: "Handler called")
26 | var expectedEvent: TextInputModeMonitor.Event?
27 | let monitor = TextInputModeMonitor(queue: .main) { event in
28 | XCTAssertEqual(OperationQueue.current, .main)
29 |
30 | expectedEvent = event
31 | expectation.fulfill()
32 | }
33 |
34 | monitor.startMonitoring()
35 | simulateDidChange()
36 | waitForExpectations(timeout: 1)
37 | monitor.stopMonitoring()
38 |
39 | if let event = expectedEvent,
40 | case let .didChange(test) = event {
41 | XCTAssertEqual(test, textInputMode)
42 | } else {
43 | XCTFail("Unexpected Event")
44 | }
45 | }
46 |
47 | private func simulateDidChange() {
48 | notificationCenter.post(name: .UITextInputCurrentInputModeDidChange,
49 | object: textInputMode)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/XestiMonitors.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'XestiMonitors'
3 | s.version = '2.12.1'
4 | s.swift_version = '4.0'
5 | s.authors = { 'J. G. Pusey' => 'ebardx@gmail.com' }
6 | s.license = { :type => 'MIT',
7 | :file => 'LICENSE.md' }
8 | s.homepage = 'https://github.com/eBardX/XestiMonitors'
9 | s.source = { :git => 'https://github.com/eBardX/XestiMonitors.git',
10 | :tag => "v#{s.version}" }
11 | s.summary = 'An extensible monitoring framework written in Swift.'
12 | s.documentation_url = 'https://ebardx.github.io/XestiMonitors/'
13 |
14 | s.ios.deployment_target = '9.0'
15 | s.osx.deployment_target = '10.10'
16 | s.tvos.deployment_target = '9.0'
17 | s.watchos.deployment_target = '2.0'
18 |
19 | s.requires_arc = true
20 |
21 | s.ios.frameworks = 'CoreLocation', 'CoreMotion', 'Foundation', 'SystemConfiguration', 'UIKit'
22 | s.osx.frameworks = 'CoreLocation', 'Foundation', 'SystemConfiguration'
23 | s.tvos.frameworks = 'CoreLocation', 'Foundation', 'SystemConfiguration', 'UIKit'
24 | s.watchos.frameworks = 'CoreLocation', 'CoreMotion', 'Foundation'
25 |
26 | s.default_subspec = 'Core'
27 |
28 | s.subspec 'Core' do |ss|
29 | ss.source_files = 'Sources/Core/**/*.swift'
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/XestiMonitors.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/XestiMonitors.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/docs/badge.svg:
--------------------------------------------------------------------------------
1 |
29 |
--------------------------------------------------------------------------------
/docs/docsets/XestiMonitors.docset/Contents/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleIdentifier
6 | com.jazzy.xestimonitors
7 | CFBundleName
8 | XestiMonitors
9 | DocSetPlatformFamily
10 | xestimonitors
11 | isDashDocset
12 |
13 | dashIndexFilePath
14 | index.html
15 | isJavaScriptEnabled
16 |
17 | DashDocSetFamily
18 | dashtoc
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/docsets/XestiMonitors.docset/Contents/Resources/Documents/img/carat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBardX/XestiMonitors/d5dc9aa24b9e84530f3f026f328cec8904215179/docs/docsets/XestiMonitors.docset/Contents/Resources/Documents/img/carat.png
--------------------------------------------------------------------------------
/docs/docsets/XestiMonitors.docset/Contents/Resources/Documents/img/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBardX/XestiMonitors/d5dc9aa24b9e84530f3f026f328cec8904215179/docs/docsets/XestiMonitors.docset/Contents/Resources/Documents/img/dash.png
--------------------------------------------------------------------------------
/docs/docsets/XestiMonitors.docset/Contents/Resources/Documents/img/gh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBardX/XestiMonitors/d5dc9aa24b9e84530f3f026f328cec8904215179/docs/docsets/XestiMonitors.docset/Contents/Resources/Documents/img/gh.png
--------------------------------------------------------------------------------
/docs/docsets/XestiMonitors.docset/Contents/Resources/Documents/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBardX/XestiMonitors/d5dc9aa24b9e84530f3f026f328cec8904215179/docs/docsets/XestiMonitors.docset/Contents/Resources/Documents/img/spinner.gif
--------------------------------------------------------------------------------
/docs/docsets/XestiMonitors.docset/Contents/Resources/Documents/js/jazzy.js:
--------------------------------------------------------------------------------
1 | window.jazzy = {'docset': false}
2 | if (typeof window.dash != 'undefined') {
3 | document.documentElement.className += ' dash'
4 | window.jazzy.docset = true
5 | }
6 | if (navigator.userAgent.match(/xcode/i)) {
7 | document.documentElement.className += ' xcode'
8 | window.jazzy.docset = true
9 | }
10 |
11 | // On doc load, toggle the URL hash discussion if present
12 | $(document).ready(function() {
13 | if (!window.jazzy.docset) {
14 | var linkToHash = $('a[href="' + window.location.hash +'"]');
15 | linkToHash.trigger("click");
16 | }
17 | });
18 |
19 | // On token click, toggle its discussion and animate token.marginLeft
20 | $(".token").click(function(event) {
21 | if (window.jazzy.docset) {
22 | return;
23 | }
24 | var link = $(this);
25 | var animationDuration = 300;
26 | $content = link.parent().parent().next();
27 | $content.slideToggle(animationDuration);
28 |
29 | // Keeps the document from jumping to the hash.
30 | var href = $(this).attr('href');
31 | if (history.pushState) {
32 | history.pushState({}, '', href);
33 | } else {
34 | location.hash = href;
35 | }
36 | event.preventDefault();
37 | });
38 |
39 | // Dumb down quotes within code blocks that delimit strings instead of quotations
40 | // https://github.com/realm/jazzy/issues/714
41 | $("code q").replaceWith(function () {
42 | return ["\"", $(this).contents(), "\""];
43 | });
44 |
--------------------------------------------------------------------------------
/docs/docsets/XestiMonitors.docset/Contents/Resources/Documents/js/jazzy.search.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | var searchIndex = lunr(function() {
3 | this.ref('url');
4 | this.field('name');
5 | });
6 |
7 | var $typeahead = $('[data-typeahead]');
8 | var $form = $typeahead.parents('form');
9 | var searchURL = $form.attr('action');
10 |
11 | function displayTemplate(result) {
12 | return result.name;
13 | }
14 |
15 | function suggestionTemplate(result) {
16 | var t = '';
17 | t += '' + result.name + '';
18 | if (result.parent_name) {
19 | t += '' + result.parent_name + '';
20 | }
21 | t += '
';
22 | return t;
23 | }
24 |
25 | $typeahead.one('focus', function() {
26 | $form.addClass('loading');
27 |
28 | $.getJSON(searchURL).then(function(searchData) {
29 | $.each(searchData, function (url, doc) {
30 | searchIndex.add({url: url, name: doc.name});
31 | });
32 |
33 | $typeahead.typeahead(
34 | {
35 | highlight: true,
36 | minLength: 3
37 | },
38 | {
39 | limit: 10,
40 | display: displayTemplate,
41 | templates: { suggestion: suggestionTemplate },
42 | source: function(query, sync) {
43 | var results = searchIndex.search(query).map(function(result) {
44 | var doc = searchData[result.ref];
45 | doc.url = result.ref;
46 | return doc;
47 | });
48 | sync(results);
49 | }
50 | }
51 | );
52 | $form.removeClass('loading');
53 | $typeahead.trigger('focus');
54 | });
55 | });
56 |
57 | var baseURL = searchURL.slice(0, -"search.json".length);
58 |
59 | $typeahead.on('typeahead:select', function(e, result) {
60 | window.location = baseURL + result.url;
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/docs/docsets/XestiMonitors.docset/Contents/Resources/docSet.dsidx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBardX/XestiMonitors/d5dc9aa24b9e84530f3f026f328cec8904215179/docs/docsets/XestiMonitors.docset/Contents/Resources/docSet.dsidx
--------------------------------------------------------------------------------
/docs/docsets/XestiMonitors.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBardX/XestiMonitors/d5dc9aa24b9e84530f3f026f328cec8904215179/docs/docsets/XestiMonitors.tgz
--------------------------------------------------------------------------------
/docs/docsets/XestiMonitors.xml:
--------------------------------------------------------------------------------
1 | 2.12.1https://eBardX.github.io/XestiMonitors/reference/docsets/XestiMonitors.tgz
2 |
--------------------------------------------------------------------------------
/docs/img/carat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBardX/XestiMonitors/d5dc9aa24b9e84530f3f026f328cec8904215179/docs/img/carat.png
--------------------------------------------------------------------------------
/docs/img/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBardX/XestiMonitors/d5dc9aa24b9e84530f3f026f328cec8904215179/docs/img/dash.png
--------------------------------------------------------------------------------
/docs/img/gh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBardX/XestiMonitors/d5dc9aa24b9e84530f3f026f328cec8904215179/docs/img/gh.png
--------------------------------------------------------------------------------
/docs/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eBardX/XestiMonitors/d5dc9aa24b9e84530f3f026f328cec8904215179/docs/img/spinner.gif
--------------------------------------------------------------------------------
/docs/js/jazzy.js:
--------------------------------------------------------------------------------
1 | window.jazzy = {'docset': false}
2 | if (typeof window.dash != 'undefined') {
3 | document.documentElement.className += ' dash'
4 | window.jazzy.docset = true
5 | }
6 | if (navigator.userAgent.match(/xcode/i)) {
7 | document.documentElement.className += ' xcode'
8 | window.jazzy.docset = true
9 | }
10 |
11 | // On doc load, toggle the URL hash discussion if present
12 | $(document).ready(function() {
13 | if (!window.jazzy.docset) {
14 | var linkToHash = $('a[href="' + window.location.hash +'"]');
15 | linkToHash.trigger("click");
16 | }
17 | });
18 |
19 | // On token click, toggle its discussion and animate token.marginLeft
20 | $(".token").click(function(event) {
21 | if (window.jazzy.docset) {
22 | return;
23 | }
24 | var link = $(this);
25 | var animationDuration = 300;
26 | $content = link.parent().parent().next();
27 | $content.slideToggle(animationDuration);
28 |
29 | // Keeps the document from jumping to the hash.
30 | var href = $(this).attr('href');
31 | if (history.pushState) {
32 | history.pushState({}, '', href);
33 | } else {
34 | location.hash = href;
35 | }
36 | event.preventDefault();
37 | });
38 |
39 | // Dumb down quotes within code blocks that delimit strings instead of quotations
40 | // https://github.com/realm/jazzy/issues/714
41 | $("code q").replaceWith(function () {
42 | return ["\"", $(this).contents(), "\""];
43 | });
44 |
--------------------------------------------------------------------------------
/docs/js/jazzy.search.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | var searchIndex = lunr(function() {
3 | this.ref('url');
4 | this.field('name');
5 | });
6 |
7 | var $typeahead = $('[data-typeahead]');
8 | var $form = $typeahead.parents('form');
9 | var searchURL = $form.attr('action');
10 |
11 | function displayTemplate(result) {
12 | return result.name;
13 | }
14 |
15 | function suggestionTemplate(result) {
16 | var t = '';
17 | t += '' + result.name + '';
18 | if (result.parent_name) {
19 | t += '' + result.parent_name + '';
20 | }
21 | t += '
';
22 | return t;
23 | }
24 |
25 | $typeahead.one('focus', function() {
26 | $form.addClass('loading');
27 |
28 | $.getJSON(searchURL).then(function(searchData) {
29 | $.each(searchData, function (url, doc) {
30 | searchIndex.add({url: url, name: doc.name});
31 | });
32 |
33 | $typeahead.typeahead(
34 | {
35 | highlight: true,
36 | minLength: 3
37 | },
38 | {
39 | limit: 10,
40 | display: displayTemplate,
41 | templates: { suggestion: suggestionTemplate },
42 | source: function(query, sync) {
43 | var results = searchIndex.search(query).map(function(result) {
44 | var doc = searchData[result.ref];
45 | doc.url = result.ref;
46 | return doc;
47 | });
48 | sync(results);
49 | }
50 | }
51 | );
52 | $form.removeClass('loading');
53 | $typeahead.trigger('focus');
54 | });
55 | });
56 |
57 | var baseURL = searchURL.slice(0, -"search.json".length);
58 |
59 | $typeahead.on('typeahead:select', function(e, result) {
60 | window.location = baseURL + result.url;
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/docs/undocumented.json:
--------------------------------------------------------------------------------
1 | {
2 | "warnings": [
3 |
4 | ],
5 | "source_directory": "/Users/jgp/Programming/Xesticode/Public/XestiMonitors"
6 | }
--------------------------------------------------------------------------------