From f5f51051540bd266bfd1db55268ed1bbab5e56f1 Mon Sep 17 00:00:00 2001 From: Dmitry Bespalov Date: Tue, 24 Oct 2017 13:14:26 +0200 Subject: [PATCH 1/5] GH-4 Added reactivation of the app after each action is generated --- SwiftMonkey/MonkeyXCTestPrivate.swift | 214 +++++++++++++++----------- 1 file changed, 124 insertions(+), 90 deletions(-) diff --git a/SwiftMonkey/MonkeyXCTestPrivate.swift b/SwiftMonkey/MonkeyXCTestPrivate.swift index 0661783..8f13d84 100644 --- a/SwiftMonkey/MonkeyXCTestPrivate.swift +++ b/SwiftMonkey/MonkeyXCTestPrivate.swift @@ -12,16 +12,16 @@ import XCTest var orientationValue: UIDeviceOrientation = .portrait /** - Extension using private funcctions from the XCTest API - to generate events. + Extension using private funcctions from the XCTest API + to generate events. - The public XCTest API is far too slow for useful random testing, - so currently using private APIs is the only option. + The public XCTest API is far too slow for useful random testing, + so currently using private APIs is the only option. - As this code is only used in your tests, and never - distributed, it will not cause problems with App Store - approval. -*/ + As this code is only used in your tests, and never + distributed, it will not cause problems with App Store + approval. + */ extension Monkey { private var sharedXCEventGenerator: XCEventGenerator { let generatorClass = unsafeBitCast(NSClassFromString("XCEventGenerator"),to: XCEventGenerator.Type.self) @@ -29,11 +29,11 @@ extension Monkey { } /** - Add a sane default set of event generation actions - using the private XCTest API. Use this function if you - just want to generate some events, and do not have - strong requirements on exactly which ones you need. - */ + Add a sane default set of event generation actions + using the private XCTest API. Use this function if you + just want to generate some events, and do not have + strong requirements on exactly which ones you need. + */ public func addDefaultXCTestPrivateActions() { addXCTestTapAction(weight: 25) addXCTestLongPressAction(weight: 1) @@ -45,21 +45,21 @@ extension Monkey { } /** - Add an action that generates a tap, with a possibility for - multiple taps with multiple fingers, using the private - XCTest API. - - - parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - - parameter multipleTapProbability: Probability that - the tap event will tap multiple times. Between 0 and 1. - - parameter multipleTouchProbability: Probability that - the tap event will use multiple fingers. Between 0 and 1. - */ + Add an action that generates a tap, with a possibility for + multiple taps with multiple fingers, using the private + XCTest API. + + - parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + - parameter multipleTapProbability: Probability that + the tap event will tap multiple times. Between 0 and 1. + - parameter multipleTouchProbability: Probability that + the tap event will use multiple fingers. Between 0 and 1. + */ public func addXCTestTapAction(weight: Double, multipleTapProbability: Double = 0.05, - multipleTouchProbability: Double = 0.05) { + multipleTouchProbability: Double = 0.05) { addAction(weight: weight) { [weak self] in let numberOfTaps: UInt if self!.r.randomDouble() < multipleTapProbability { @@ -80,131 +80,154 @@ extension Monkey { } let semaphore = DispatchSemaphore(value: 0) - self!.sharedXCEventGenerator.tapAtTouchLocations(locations, numberOfTaps: numberOfTaps, orientation: orientationValue) { - semaphore.signal() + self!.sharedXCEventGenerator.tapAtTouchLocations(locations, + numberOfTaps: numberOfTaps, + orientation: orientationValue) { [weak self] in + semaphore.signal() + self?.reactivateApplicationIfNeeded() } semaphore.wait() } } /** - Add an action that generates a long press event - using the private XCTest API. - - - Parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - */ + Add an action that generates a long press event + using the private XCTest API. + + - Parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + */ public func addXCTestLongPressAction(weight: Double) { addAction(weight: weight) { [weak self] in let point = self!.randomPoint() let semaphore = DispatchSemaphore(value: 0) - self!.sharedXCEventGenerator.pressAtPoint(point, forDuration: 0.5, orientation: orientationValue) { - semaphore.signal() + self!.sharedXCEventGenerator.pressAtPoint(point, forDuration: 0.5, + orientation: orientationValue) { [weak self] in + semaphore.signal() + self?.reactivateApplicationIfNeeded() } semaphore.wait() } } /** - Add an action that generates a drag event from one random - screen position to another using the private XCTest API. - - - Parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - */ + Add an action that generates a drag event from one random + screen position to another using the private XCTest API. + + - Parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + */ public func addXCTestDragAction(weight: Double) { addAction(weight: weight) { [weak self] in let start = self!.randomPointAvoidingPanelAreas() let end = self!.randomPoint() - + let semaphore = DispatchSemaphore(value: 0) - self!.sharedXCEventGenerator.pressAtPoint(start, forDuration: 0, liftAtPoint: end, velocity: 1000, orientation: orientationValue, name: "Monkey drag" as NSString) { - semaphore.signal() + self!.sharedXCEventGenerator.pressAtPoint(start, + forDuration: 0, + liftAtPoint: end, + velocity: 1000, + orientation: orientationValue, + name: "Monkey drag" as NSString) { [weak self] in + semaphore.signal() + self?.reactivateApplicationIfNeeded() } semaphore.wait() } } /** - Add an action that generates a pinch close gesture - at a random screen position using the private XCTest API. - - - Parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - */ + Add an action that generates a pinch close gesture + at a random screen position using the private XCTest API. + + - Parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + */ public func addXCTestPinchCloseAction(weight: Double) { addAction(weight: weight) { [weak self] in let rect = self!.randomRect(sizeFraction: 2) let scale = 1 / CGFloat(self!.r.randomDouble() * 4 + 1) let semaphore = DispatchSemaphore(value: 0) - self!.sharedXCEventGenerator.pinchInRect(rect, withScale: scale, velocity: 1, orientation: orientationValue) { - semaphore.signal() + self!.sharedXCEventGenerator.pinchInRect(rect, + withScale: scale, + velocity: 1, + orientation: orientationValue) { [weak self] in + semaphore.signal() + self?.reactivateApplicationIfNeeded() } semaphore.wait() } } /** - Add an action that generates a pinch open gesture - at a random screen position using the private XCTest API. - - - Parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - */ + Add an action that generates a pinch open gesture + at a random screen position using the private XCTest API. + + - Parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + */ public func addXCTestPinchOpenAction(weight: Double) { addAction(weight: weight) { [weak self] in let rect = self!.randomRect(sizeFraction: 2) let scale = CGFloat(self!.r.randomDouble() * 4 + 1) let semaphore = DispatchSemaphore(value: 0) - self!.sharedXCEventGenerator.pinchInRect(rect, withScale: scale, velocity: 3, orientation: orientationValue) { - semaphore.signal() + self!.sharedXCEventGenerator.pinchInRect(rect, + withScale: scale, + velocity: 3, + orientation: orientationValue) { [weak self] in + semaphore.signal() + self?.reactivateApplicationIfNeeded() } semaphore.wait() } } /** - Add an action that generates a rotation gesture - at a random screen position over a random angle - using the private XCTest API. - - - Parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - */ + Add an action that generates a rotation gesture + at a random screen position over a random angle + using the private XCTest API. + + - Parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + */ public func addXCTestRotateAction(weight: Double) { addAction(weight: weight) { [weak self] in let rect = self!.randomRect(sizeFraction: 2) let angle = CGFloat(self!.r.randomDouble() * 2 * 3.141592) let semaphore = DispatchSemaphore(value: 0) - self!.sharedXCEventGenerator.rotateInRect(rect, withRotation: angle, velocity: 5, orientation: orientationValue) { - semaphore.signal() + self!.sharedXCEventGenerator.rotateInRect(rect, + withRotation: angle, + velocity: 5, + orientation: orientationValue) { [weak self] in + semaphore.signal() + self?.reactivateApplicationIfNeeded() } semaphore.wait() } } /** - Add an action that generates a device rotation event - using the private XCTest API. Does not currently work! - - - Parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - */ + Add an action that generates a device rotation event + using the private XCTest API. Does not currently work! + + - Parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + */ public func addXCTestOrientationAction(weight: Double) { addAction(weight: weight) { [weak self] in let orientations: [UIDeviceOrientation] = [ @@ -214,12 +237,23 @@ extension Monkey { .landscapeRight, .faceUp, .faceDown, - ] + ] let index = Int(self!.r.randomUInt32() % UInt32(orientations.count)) orientationValue = orientations[index] } } + + private func reactivateApplicationIfNeeded() { + if #available(iOS 9.0, *) { + DispatchQueue.main.async { + if XCUIApplication().state != .runningForeground{ + XCUIApplication().activate() + } + } + } + } + } @objc protocol XCEventGenerator { From 11367693b77b65d2a5a2d6db1bd96cc8217938b3 Mon Sep 17 00:00:00 2001 From: Dmitry Bespalov Date: Thu, 26 Oct 2017 16:02:18 +0200 Subject: [PATCH 2/5] GH-4 Don't act if in background --- SwiftMonkey/MonkeyXCTestPrivate.swift | 32 ++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/SwiftMonkey/MonkeyXCTestPrivate.swift b/SwiftMonkey/MonkeyXCTestPrivate.swift index 8f13d84..8a8e177 100644 --- a/SwiftMonkey/MonkeyXCTestPrivate.swift +++ b/SwiftMonkey/MonkeyXCTestPrivate.swift @@ -28,6 +28,13 @@ extension Monkey { return generatorClass.sharedGenerator() } + private var isInForeground: Bool { + if #available(iOS 9.0, *) { + return XCUIApplication().state == .runningForeground + } + return true + } + /** Add a sane default set of event generation actions using the private XCTest API. Use this function if you @@ -61,6 +68,7 @@ extension Monkey { public func addXCTestTapAction(weight: Double, multipleTapProbability: Double = 0.05, multipleTouchProbability: Double = 0.05) { addAction(weight: weight) { [weak self] in + guard self?.isInForeground == true else { return } let numberOfTaps: UInt if self!.r.randomDouble() < multipleTapProbability { numberOfTaps = UInt(self!.r.randomUInt32() % 2) + 2 @@ -83,8 +91,8 @@ extension Monkey { self!.sharedXCEventGenerator.tapAtTouchLocations(locations, numberOfTaps: numberOfTaps, orientation: orientationValue) { [weak self] in - semaphore.signal() self?.reactivateApplicationIfNeeded() + semaphore.signal() } semaphore.wait() } @@ -101,12 +109,14 @@ extension Monkey { */ public func addXCTestLongPressAction(weight: Double) { addAction(weight: weight) { [weak self] in + guard self?.isInForeground == true else { return } + let point = self!.randomPoint() let semaphore = DispatchSemaphore(value: 0) self!.sharedXCEventGenerator.pressAtPoint(point, forDuration: 0.5, orientation: orientationValue) { [weak self] in - semaphore.signal() self?.reactivateApplicationIfNeeded() + semaphore.signal() } semaphore.wait() } @@ -123,6 +133,8 @@ extension Monkey { */ public func addXCTestDragAction(weight: Double) { addAction(weight: weight) { [weak self] in + guard self?.isInForeground == true else { return } + let start = self!.randomPointAvoidingPanelAreas() let end = self!.randomPoint() @@ -133,8 +145,8 @@ extension Monkey { velocity: 1000, orientation: orientationValue, name: "Monkey drag" as NSString) { [weak self] in - semaphore.signal() self?.reactivateApplicationIfNeeded() + semaphore.signal() } semaphore.wait() } @@ -151,6 +163,8 @@ extension Monkey { */ public func addXCTestPinchCloseAction(weight: Double) { addAction(weight: weight) { [weak self] in + guard self?.isInForeground == true else { return } + let rect = self!.randomRect(sizeFraction: 2) let scale = 1 / CGFloat(self!.r.randomDouble() * 4 + 1) @@ -159,8 +173,8 @@ extension Monkey { withScale: scale, velocity: 1, orientation: orientationValue) { [weak self] in - semaphore.signal() self?.reactivateApplicationIfNeeded() + semaphore.signal() } semaphore.wait() } @@ -177,6 +191,8 @@ extension Monkey { */ public func addXCTestPinchOpenAction(weight: Double) { addAction(weight: weight) { [weak self] in + guard self?.isInForeground == true else { return } + let rect = self!.randomRect(sizeFraction: 2) let scale = CGFloat(self!.r.randomDouble() * 4 + 1) @@ -185,8 +201,8 @@ extension Monkey { withScale: scale, velocity: 3, orientation: orientationValue) { [weak self] in - semaphore.signal() self?.reactivateApplicationIfNeeded() + semaphore.signal() } semaphore.wait() } @@ -204,6 +220,8 @@ extension Monkey { */ public func addXCTestRotateAction(weight: Double) { addAction(weight: weight) { [weak self] in + guard self?.isInForeground == true else { return } + let rect = self!.randomRect(sizeFraction: 2) let angle = CGFloat(self!.r.randomDouble() * 2 * 3.141592) @@ -212,8 +230,8 @@ extension Monkey { withRotation: angle, velocity: 5, orientation: orientationValue) { [weak self] in - semaphore.signal() self?.reactivateApplicationIfNeeded() + semaphore.signal() } semaphore.wait() } @@ -230,6 +248,8 @@ extension Monkey { */ public func addXCTestOrientationAction(weight: Double) { addAction(weight: weight) { [weak self] in + guard self?.isInForeground == true else { return } + let orientations: [UIDeviceOrientation] = [ .portrait, .portraitUpsideDown, From 22720d294bdd6d0529069a0dacf39531681afe63 Mon Sep 17 00:00:00 2001 From: Dmitry Bespalov Date: Wed, 1 Nov 2017 15:38:00 +0100 Subject: [PATCH 3/5] GH-4 Refactored into method and used in both private and ui automation apis --- SwiftMonkey/MonkeyUIAutomation.swift | 48 +++++++------- SwiftMonkey/MonkeyXCTestPrivate.swift | 96 ++++++++++++--------------- 2 files changed, 67 insertions(+), 77 deletions(-) diff --git a/SwiftMonkey/MonkeyUIAutomation.swift b/SwiftMonkey/MonkeyUIAutomation.swift index 2ceb784..5ebb353 100644 --- a/SwiftMonkey/MonkeyUIAutomation.swift +++ b/SwiftMonkey/MonkeyUIAutomation.swift @@ -62,9 +62,9 @@ extension Monkey { of all relative probabilities. */ public func addUIAutomationSingleTapAction(weight: Double) { - addAction(weight: weight) { [weak self] in + addAction(weight: weight, action: actInForeground { [weak self] in eventGenerator.sendTap(self!.randomPoint()) - } + }) } /** @@ -85,7 +85,7 @@ extension Monkey { */ public func addUIAutomationTapAction(weight: Double, multipleTapProbability: Double = 0.05, multipleTouchProbability: Double = 0.05, longPressProbability: Double = 0.05) { - addAction(weight: weight) { [weak self] in + addAction(weight: weight, action: actInForeground { [weak self] in let numberOfTaps: Int if self!.r.randomDouble() Void + + /** + Wrap your action with this function to make sure your actions are dispatched inside the app under test + and not in some other app that the Monkey randomly opened. + */ + func actInForeground(_ action: @escaping ActionClousre) -> ActionClousre { + return { + guard #available(iOS 9.0, *) else { + action() + return + } + let closure: ActionClousre = { + if XCUIApplication().state != .runningForeground { + XCUIApplication().activate() + } + action() + } + if Thread.isMainThread { + closure() + } else { + DispatchQueue.main.async(execute: closure) + } } - return true } /** @@ -67,8 +86,7 @@ extension Monkey { */ public func addXCTestTapAction(weight: Double, multipleTapProbability: Double = 0.05, multipleTouchProbability: Double = 0.05) { - addAction(weight: weight) { [weak self] in - guard self?.isInForeground == true else { return } + addAction(weight: weight, action: actInForeground { [weak self] in let numberOfTaps: UInt if self!.r.randomDouble() < multipleTapProbability { numberOfTaps = UInt(self!.r.randomUInt32() % 2) + 2 @@ -90,12 +108,11 @@ extension Monkey { let semaphore = DispatchSemaphore(value: 0) self!.sharedXCEventGenerator.tapAtTouchLocations(locations, numberOfTaps: numberOfTaps, - orientation: orientationValue) { [weak self] in - self?.reactivateApplicationIfNeeded() + orientation: orientationValue) { semaphore.signal() } semaphore.wait() - } + }) } /** @@ -108,18 +125,15 @@ extension Monkey { of all relative probabilities. */ public func addXCTestLongPressAction(weight: Double) { - addAction(weight: weight) { [weak self] in - guard self?.isInForeground == true else { return } - + addAction(weight: weight, action: actInForeground { [weak self] in let point = self!.randomPoint() let semaphore = DispatchSemaphore(value: 0) self!.sharedXCEventGenerator.pressAtPoint(point, forDuration: 0.5, - orientation: orientationValue) { [weak self] in - self?.reactivateApplicationIfNeeded() + orientation: orientationValue) { semaphore.signal() } semaphore.wait() - } + }) } /** @@ -132,9 +146,7 @@ extension Monkey { of all relative probabilities. */ public func addXCTestDragAction(weight: Double) { - addAction(weight: weight) { [weak self] in - guard self?.isInForeground == true else { return } - + addAction(weight: weight, action: actInForeground { [weak self] in let start = self!.randomPointAvoidingPanelAreas() let end = self!.randomPoint() @@ -144,12 +156,11 @@ extension Monkey { liftAtPoint: end, velocity: 1000, orientation: orientationValue, - name: "Monkey drag" as NSString) { [weak self] in - self?.reactivateApplicationIfNeeded() + name: "Monkey drag" as NSString) { semaphore.signal() } semaphore.wait() - } + }) } /** @@ -162,9 +173,7 @@ extension Monkey { of all relative probabilities. */ public func addXCTestPinchCloseAction(weight: Double) { - addAction(weight: weight) { [weak self] in - guard self?.isInForeground == true else { return } - + addAction(weight: weight, action: actInForeground { [weak self] in let rect = self!.randomRect(sizeFraction: 2) let scale = 1 / CGFloat(self!.r.randomDouble() * 4 + 1) @@ -172,12 +181,11 @@ extension Monkey { self!.sharedXCEventGenerator.pinchInRect(rect, withScale: scale, velocity: 1, - orientation: orientationValue) { [weak self] in - self?.reactivateApplicationIfNeeded() + orientation: orientationValue) { semaphore.signal() } semaphore.wait() - } + }) } /** @@ -190,9 +198,7 @@ extension Monkey { of all relative probabilities. */ public func addXCTestPinchOpenAction(weight: Double) { - addAction(weight: weight) { [weak self] in - guard self?.isInForeground == true else { return } - + addAction(weight: weight, action: actInForeground { [weak self] in let rect = self!.randomRect(sizeFraction: 2) let scale = CGFloat(self!.r.randomDouble() * 4 + 1) @@ -200,12 +206,11 @@ extension Monkey { self!.sharedXCEventGenerator.pinchInRect(rect, withScale: scale, velocity: 3, - orientation: orientationValue) { [weak self] in - self?.reactivateApplicationIfNeeded() + orientation: orientationValue) { semaphore.signal() } semaphore.wait() - } + }) } /** @@ -219,9 +224,7 @@ extension Monkey { of all relative probabilities. */ public func addXCTestRotateAction(weight: Double) { - addAction(weight: weight) { [weak self] in - guard self?.isInForeground == true else { return } - + addAction(weight: weight, action: actInForeground { [weak self] in let rect = self!.randomRect(sizeFraction: 2) let angle = CGFloat(self!.r.randomDouble() * 2 * 3.141592) @@ -229,12 +232,11 @@ extension Monkey { self!.sharedXCEventGenerator.rotateInRect(rect, withRotation: angle, velocity: 5, - orientation: orientationValue) { [weak self] in - self?.reactivateApplicationIfNeeded() + orientation: orientationValue) { semaphore.signal() } semaphore.wait() - } + }) } /** @@ -247,9 +249,7 @@ extension Monkey { of all relative probabilities. */ public func addXCTestOrientationAction(weight: Double) { - addAction(weight: weight) { [weak self] in - guard self?.isInForeground == true else { return } - + addAction(weight: weight, action: actInForeground { [weak self] in let orientations: [UIDeviceOrientation] = [ .portrait, .portraitUpsideDown, @@ -261,17 +261,7 @@ extension Monkey { let index = Int(self!.r.randomUInt32() % UInt32(orientations.count)) orientationValue = orientations[index] - } - } - - private func reactivateApplicationIfNeeded() { - if #available(iOS 9.0, *) { - DispatchQueue.main.async { - if XCUIApplication().state != .runningForeground{ - XCUIApplication().activate() - } - } - } + }) } } From 0ff3522023c09f00f317b45c8ab847be565bf491 Mon Sep 17 00:00:00 2001 From: Dmitry Bespalov Date: Wed, 1 Nov 2017 15:43:29 +0100 Subject: [PATCH 4/5] GH-4 Moved call to addActions method --- SwiftMonkey/Monkey.swift | 31 +++- SwiftMonkey/MonkeyUIAutomation.swift | 48 ++--- SwiftMonkey/MonkeyXCTestPrivate.swift | 252 +++++++++++--------------- 3 files changed, 157 insertions(+), 174 deletions(-) diff --git a/SwiftMonkey/Monkey.swift b/SwiftMonkey/Monkey.swift index 9b3562c..5e9117b 100644 --- a/SwiftMonkey/Monkey.swift +++ b/SwiftMonkey/Monkey.swift @@ -7,6 +7,7 @@ // import UIKit +import XCTest /** A general-purpose class for implementing randomised @@ -193,7 +194,7 @@ public class Monkey { */ public func addAction(weight: Double, action: @escaping () -> Void) { totalWeight += weight - randomActions.append((accumulatedWeight: totalWeight, action: action)) + randomActions.append((accumulatedWeight: totalWeight, action: actInForeground(action))) } /** @@ -206,7 +207,33 @@ public class Monkey { is generated. */ public func addAction(interval: Int, action: @escaping () -> Void) { - regularActions.append((interval: interval, action: action)) + regularActions.append((interval: interval, action: actInForeground(action))) + } + + typealias ActionClousre = () -> Void + + /** + Wrap your action with this function to make sure your actions are dispatched inside the app under test + and not in some other app that the Monkey randomly opened. + */ + func actInForeground(_ action: @escaping ActionClousre) -> ActionClousre { + return { + guard #available(iOS 9.0, *) else { + action() + return + } + let closure: ActionClousre = { + if XCUIApplication().state != .runningForeground { + XCUIApplication().activate() + } + action() + } + if Thread.isMainThread { + closure() + } else { + DispatchQueue.main.async(execute: closure) + } + } } /** diff --git a/SwiftMonkey/MonkeyUIAutomation.swift b/SwiftMonkey/MonkeyUIAutomation.swift index 5ebb353..2ceb784 100644 --- a/SwiftMonkey/MonkeyUIAutomation.swift +++ b/SwiftMonkey/MonkeyUIAutomation.swift @@ -62,9 +62,9 @@ extension Monkey { of all relative probabilities. */ public func addUIAutomationSingleTapAction(weight: Double) { - addAction(weight: weight, action: actInForeground { [weak self] in + addAction(weight: weight) { [weak self] in eventGenerator.sendTap(self!.randomPoint()) - }) + } } /** @@ -85,7 +85,7 @@ extension Monkey { */ public func addUIAutomationTapAction(weight: Double, multipleTapProbability: Double = 0.05, multipleTouchProbability: Double = 0.05, longPressProbability: Double = 0.05) { - addAction(weight: weight, action: actInForeground { [weak self] in + addAction(weight: weight) { [weak self] in let numberOfTaps: Int if self!.r.randomDouble() Void - /** - Wrap your action with this function to make sure your actions are dispatched inside the app under test - and not in some other app that the Monkey randomly opened. - */ - func actInForeground(_ action: @escaping ActionClousre) -> ActionClousre { - return { - guard #available(iOS 9.0, *) else { - action() - return - } - let closure: ActionClousre = { - if XCUIApplication().state != .runningForeground { - XCUIApplication().activate() - } - action() - } - if Thread.isMainThread { - closure() - } else { - DispatchQueue.main.async(execute: closure) - } - } - } - - /** - Add a sane default set of event generation actions - using the private XCTest API. Use this function if you - just want to generate some events, and do not have - strong requirements on exactly which ones you need. - */ + Add a sane default set of event generation actions + using the private XCTest API. Use this function if you + just want to generate some events, and do not have + strong requirements on exactly which ones you need. + */ public func addDefaultXCTestPrivateActions() { addXCTestTapAction(weight: 25) addXCTestLongPressAction(weight: 1) @@ -71,22 +45,22 @@ extension Monkey { } /** - Add an action that generates a tap, with a possibility for - multiple taps with multiple fingers, using the private - XCTest API. - - - parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - - parameter multipleTapProbability: Probability that - the tap event will tap multiple times. Between 0 and 1. - - parameter multipleTouchProbability: Probability that - the tap event will use multiple fingers. Between 0 and 1. - */ + Add an action that generates a tap, with a possibility for + multiple taps with multiple fingers, using the private + XCTest API. + + - parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + - parameter multipleTapProbability: Probability that + the tap event will tap multiple times. Between 0 and 1. + - parameter multipleTouchProbability: Probability that + the tap event will use multiple fingers. Between 0 and 1. + */ public func addXCTestTapAction(weight: Double, multipleTapProbability: Double = 0.05, - multipleTouchProbability: Double = 0.05) { - addAction(weight: weight, action: actInForeground { [weak self] in + multipleTouchProbability: Double = 0.05) { + addAction(weight: weight) { [weak self] in let numberOfTaps: UInt if self!.r.randomDouble() < multipleTapProbability { numberOfTaps = UInt(self!.r.randomUInt32() % 2) + 2 @@ -106,150 +80,133 @@ extension Monkey { } let semaphore = DispatchSemaphore(value: 0) - self!.sharedXCEventGenerator.tapAtTouchLocations(locations, - numberOfTaps: numberOfTaps, - orientation: orientationValue) { - semaphore.signal() + self!.sharedXCEventGenerator.tapAtTouchLocations(locations, numberOfTaps: numberOfTaps, orientation: orientationValue) { + semaphore.signal() } semaphore.wait() - }) + } } /** - Add an action that generates a long press event - using the private XCTest API. - - - Parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - */ + Add an action that generates a long press event + using the private XCTest API. + + - Parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + */ public func addXCTestLongPressAction(weight: Double) { - addAction(weight: weight, action: actInForeground { [weak self] in + addAction(weight: weight) { [weak self] in let point = self!.randomPoint() let semaphore = DispatchSemaphore(value: 0) - self!.sharedXCEventGenerator.pressAtPoint(point, forDuration: 0.5, - orientation: orientationValue) { - semaphore.signal() + self!.sharedXCEventGenerator.pressAtPoint(point, forDuration: 0.5, orientation: orientationValue) { + semaphore.signal() } semaphore.wait() - }) + } } /** - Add an action that generates a drag event from one random - screen position to another using the private XCTest API. - - - Parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - */ + Add an action that generates a drag event from one random + screen position to another using the private XCTest API. + + - Parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + */ public func addXCTestDragAction(weight: Double) { - addAction(weight: weight, action: actInForeground { [weak self] in + addAction(weight: weight) { [weak self] in let start = self!.randomPointAvoidingPanelAreas() let end = self!.randomPoint() - + let semaphore = DispatchSemaphore(value: 0) - self!.sharedXCEventGenerator.pressAtPoint(start, - forDuration: 0, - liftAtPoint: end, - velocity: 1000, - orientation: orientationValue, - name: "Monkey drag" as NSString) { - semaphore.signal() + self!.sharedXCEventGenerator.pressAtPoint(start, forDuration: 0, liftAtPoint: end, velocity: 1000, orientation: orientationValue, name: "Monkey drag" as NSString) { + semaphore.signal() } semaphore.wait() - }) + } } /** - Add an action that generates a pinch close gesture - at a random screen position using the private XCTest API. - - - Parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - */ + Add an action that generates a pinch close gesture + at a random screen position using the private XCTest API. + + - Parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + */ public func addXCTestPinchCloseAction(weight: Double) { - addAction(weight: weight, action: actInForeground { [weak self] in + addAction(weight: weight) { [weak self] in let rect = self!.randomRect(sizeFraction: 2) let scale = 1 / CGFloat(self!.r.randomDouble() * 4 + 1) let semaphore = DispatchSemaphore(value: 0) - self!.sharedXCEventGenerator.pinchInRect(rect, - withScale: scale, - velocity: 1, - orientation: orientationValue) { - semaphore.signal() + self!.sharedXCEventGenerator.pinchInRect(rect, withScale: scale, velocity: 1, orientation: orientationValue) { + semaphore.signal() } semaphore.wait() - }) + } } /** - Add an action that generates a pinch open gesture - at a random screen position using the private XCTest API. - - - Parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - */ + Add an action that generates a pinch open gesture + at a random screen position using the private XCTest API. + + - Parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + */ public func addXCTestPinchOpenAction(weight: Double) { - addAction(weight: weight, action: actInForeground { [weak self] in + addAction(weight: weight) { [weak self] in let rect = self!.randomRect(sizeFraction: 2) let scale = CGFloat(self!.r.randomDouble() * 4 + 1) let semaphore = DispatchSemaphore(value: 0) - self!.sharedXCEventGenerator.pinchInRect(rect, - withScale: scale, - velocity: 3, - orientation: orientationValue) { - semaphore.signal() + self!.sharedXCEventGenerator.pinchInRect(rect, withScale: scale, velocity: 3, orientation: orientationValue) { + semaphore.signal() } semaphore.wait() - }) + } } /** - Add an action that generates a rotation gesture - at a random screen position over a random angle - using the private XCTest API. - - - Parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - */ + Add an action that generates a rotation gesture + at a random screen position over a random angle + using the private XCTest API. + + - Parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + */ public func addXCTestRotateAction(weight: Double) { - addAction(weight: weight, action: actInForeground { [weak self] in + addAction(weight: weight) { [weak self] in let rect = self!.randomRect(sizeFraction: 2) let angle = CGFloat(self!.r.randomDouble() * 2 * 3.141592) let semaphore = DispatchSemaphore(value: 0) - self!.sharedXCEventGenerator.rotateInRect(rect, - withRotation: angle, - velocity: 5, - orientation: orientationValue) { - semaphore.signal() + self!.sharedXCEventGenerator.rotateInRect(rect, withRotation: angle, velocity: 5, orientation: orientationValue) { + semaphore.signal() } semaphore.wait() - }) + } } /** - Add an action that generates a device rotation event - using the private XCTest API. Does not currently work! - - - Parameter weight: The relative probability of this - event being generated. Can be any value larger than - zero. Probabilities will be normalised to the sum - of all relative probabilities. - */ + Add an action that generates a device rotation event + using the private XCTest API. Does not currently work! + + - Parameter weight: The relative probability of this + event being generated. Can be any value larger than + zero. Probabilities will be normalised to the sum + of all relative probabilities. + */ public func addXCTestOrientationAction(weight: Double) { - addAction(weight: weight, action: actInForeground { [weak self] in + addAction(weight: weight) { [weak self] in let orientations: [UIDeviceOrientation] = [ .portrait, .portraitUpsideDown, @@ -257,13 +214,12 @@ extension Monkey { .landscapeRight, .faceUp, .faceDown, - ] + ] let index = Int(self!.r.randomUInt32() % UInt32(orientations.count)) orientationValue = orientations[index] - }) + } } - } @objc protocol XCEventGenerator { From 1f7bfbbf6736896562ab5d67f2ec929e75bf7b03 Mon Sep 17 00:00:00 2001 From: Dmitry Bespalov Date: Wed, 1 Nov 2017 19:31:42 +0100 Subject: [PATCH 5/5] GH-4 Rename and replace with typealias --- SwiftMonkey/Monkey.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/SwiftMonkey/Monkey.swift b/SwiftMonkey/Monkey.swift index 5e9117b..da52c49 100644 --- a/SwiftMonkey/Monkey.swift +++ b/SwiftMonkey/Monkey.swift @@ -60,13 +60,15 @@ import XCTest ``` */ public class Monkey { + public typealias ActionClosure = () -> Void + var r: Random let frame: CGRect - var randomActions: [(accumulatedWeight: Double, action: () -> Void)] + var randomActions: [(accumulatedWeight: Double, action: ActionClosure)] var totalWeight: Double - var regularActions: [(interval: Int, action: () -> Void)] + var regularActions: [(interval: Int, action: ActionClosure)] var actionCounter = 0 /** @@ -192,7 +194,7 @@ public class Monkey { - parameter action: The block to run when this event is generated. */ - public func addAction(weight: Double, action: @escaping () -> Void) { + public func addAction(weight: Double, action: @escaping ActionClosure) { totalWeight += weight randomActions.append((accumulatedWeight: totalWeight, action: actInForeground(action))) } @@ -206,23 +208,21 @@ public class Monkey { - parameter action: The block to run when this event is generated. */ - public func addAction(interval: Int, action: @escaping () -> Void) { + public func addAction(interval: Int, action: @escaping ActionClosure) { regularActions.append((interval: interval, action: actInForeground(action))) } - typealias ActionClousre = () -> Void - /** Wrap your action with this function to make sure your actions are dispatched inside the app under test and not in some other app that the Monkey randomly opened. */ - func actInForeground(_ action: @escaping ActionClousre) -> ActionClousre { + func actInForeground(_ action: @escaping ActionClosure) -> ActionClosure { return { guard #available(iOS 9.0, *) else { action() return } - let closure: ActionClousre = { + let closure: ActionClosure = { if XCUIApplication().state != .runningForeground { XCUIApplication().activate() }