(constructor:() -> T, action: (T)->Any, shouldLeak: Bool = false) where T: AnyObject {
52 |
53 | var mayBeLeaking: T?
54 | let leaksAnalyzer = LeaksAnalyzer()
55 |
56 | var resultThatMightCauseLeak: Any? = nil
57 |
58 | autoreleasepool {
59 |
60 | leaksAnalyzer.leakedObject = nil
61 |
62 | //Instantiate the object that will be analyzed
63 | mayBeLeaking = constructor()
64 |
65 | //To call viewDidLoad on the vc
66 | view(mayBeLeaking)
67 |
68 | leaksAnalyzer.analize(mayBeLeaking!)
69 |
70 | //Run the action that will be analyzed
71 |
72 | resultThatMightCauseLeak = action(mayBeLeaking!)
73 |
74 | //Set to nil. If the analyzer still has an instance, that's a leak
75 | mayBeLeaking = nil
76 | }
77 |
78 | if shouldLeak {
79 | expect(leaksAnalyzer.leakedObject).toEventuallyNot(beNil())
80 | } else {
81 | expect(resultThatMightCauseLeak).toNot(beNil())
82 | expect(leaksAnalyzer.leakedObject).toEventually(beNil())
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/SpecLeaks/Classes/Expectation+Leaks.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Expectation+Leaks.swift
3 | // UnitTestLeaks
4 | //
5 | // Created by Leandro Perez on 03/02/2018.
6 | // Copyright © 2018 Leandro Perez. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Nimble
11 |
12 | public typealias LeakTestConstructor = () -> AnyObject
13 |
14 | extension Expectation where T==LeakTestConstructor {
15 |
16 | public func toNotLeak(timeout: DispatchTimeInterval = AsyncDefaults.timeout, pollInterval: DispatchTimeInterval = AsyncDefaults.pollInterval, description: String? = nil, shouldFail: Bool = false) {
17 | do {
18 | guard let constructor = try expression.evaluate() else {
19 | fail()
20 | return
21 | }
22 | AnalyzeLeak().execute(constructor: constructor, shouldLeak: shouldFail)
23 | } catch {
24 | fail()
25 | }
26 | }
27 |
28 | public func toLeak() {
29 | self.toNotLeak(timeout: AsyncDefaults.timeout, pollInterval: AsyncDefaults.pollInterval, description: nil, shouldFail: true)
30 | }
31 |
32 | public func toNotLeakWhen( shouldFail: Bool = false, _ action: (P)->Void) where P: AnyObject {
33 | do {
34 | guard let constructor = try expression.evaluate() else {
35 | fail()
36 | return
37 | }
38 | let castedConstructor : () -> P = { constructor() as! P }
39 |
40 | AnalyzeLeakAction().execute(constructor: castedConstructor, action: action, shouldLeak: shouldFail)
41 | } catch {
42 | fail()
43 | }
44 | }
45 |
46 | public func toLeakWhen
(shouldFail: Bool = false, _ action: (P)->Void) where P: AnyObject {
47 | self.toNotLeakWhen(shouldFail: true, action)
48 | }
49 |
50 | public func toNotLeakWhen
( shouldFail: Bool = false, _ action: (P)->Any) where P: AnyObject {
51 | do {
52 | guard let constructor = try expression.evaluate() else {
53 | fail()
54 | return
55 | }
56 | let castedConstructor : () -> P = { constructor() as! P }
57 |
58 | AnalyzeLeakAction().execute(constructor: castedConstructor, action: action, shouldLeak: shouldFail)
59 | } catch {
60 | fail()
61 | }
62 | }
63 |
64 | public func toLeakWhen
(shouldFail: Bool = false, _ action: (P)->Any) where P: AnyObject {
65 | self.toNotLeakWhen(shouldFail: true, action)
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/SpecLeaks/Classes/LeakTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LeakTest.swift
3 | // Nimble
4 | //
5 | // Created by Leandro Perez on 01/04/2018.
6 | //
7 |
8 | import Foundation
9 | import Quick
10 | import Nimble
11 |
12 | //public typealias LeakTestConstructor = () -> AnyObject
13 |
14 | public struct LeakTest {
15 | let constructor: LeakTestConstructor
16 |
17 | public init(constructor:@escaping LeakTestConstructor) {
18 | self.constructor = constructor
19 | }
20 |
21 | internal func isLeaking() -> Bool {
22 | weak var leaked: AnyObject? = nil
23 |
24 | autoreleasepool {
25 |
26 | var evaluated: AnyObject? = self.constructor()
27 |
28 | //To call viewDidLoad on the vc
29 | view(evaluated)
30 |
31 | leaked = evaluated
32 | evaluated = nil
33 | }
34 |
35 | return leaked != nil
36 | }
37 |
38 | internal func isLeaking
( when action: (P) -> Any) -> PredicateStatus where P: AnyObject {
39 | weak var leaked: AnyObject? = nil
40 |
41 | var failed = false
42 | var actionResult: Any? = nil
43 |
44 | autoreleasepool {
45 |
46 | var evaluated: P? = self.constructor() as? P
47 |
48 | if evaluated == nil {
49 | failed = true
50 | } else {
51 | actionResult = action(evaluated!)
52 |
53 | //To call viewDidLoad on the vc
54 | view(evaluated)
55 |
56 | leaked = evaluated
57 | evaluated = nil
58 | }
59 | }
60 |
61 | if failed || actionResult == nil {
62 | return PredicateStatus.fail
63 | }
64 |
65 | return PredicateStatus.init(bool: leaked != nil)
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/SpecLeaks/Classes/LeaksAnalyzer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LeaksAnalyzer.swift
3 | // UnitTestLeaks
4 | //
5 | // Created by Leandro Perez on 03/02/2018.
6 | // Copyright © 2018 Leandro Perez. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class LeaksAnalyzer {
12 | weak var leakedObject: AnyObject?
13 |
14 | func analize(_ leakingObject: AnyObject) {
15 | self.leakedObject = leakingObject
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SpecLeaks/Classes/Matchers.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Matchers.swift
3 | // Nimble
4 | //
5 | // Created by Leandro Perez on 01/04/2018.
6 | //
7 |
8 | import Foundation
9 | import Quick
10 | import Nimble
11 |
12 | public func leak() -> Predicate {
13 |
14 | return Predicate.simple("leak") { expression in
15 |
16 | guard let leakTest = try expression.evaluate() else {
17 | return PredicateStatus.fail
18 | }
19 |
20 | return PredicateStatus(bool: leakTest.isLeaking())
21 | }
22 | }
23 |
24 | public func leakWhen(_ action : @escaping (P) -> Any) -> Predicate where P: AnyObject {
25 |
26 | return Predicate.simple("leak when") { expression in
27 |
28 | guard let leakTest = try expression.evaluate() else {
29 | return PredicateStatus.fail
30 | }
31 |
32 | return leakTest.isLeaking(when: action)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/SpecLeaks/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SpecLeaks/SpecLeaks.h:
--------------------------------------------------------------------------------
1 | //
2 | // SpecLeaks.h
3 | // SpecLeaks
4 | //
5 | // Created by Ruiz, Josué on 5/12/19.
6 | // Copyright © 2019 com.lmp.specleaks. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for SpecLeaks.
12 | FOUNDATION_EXPORT double SpecLeaksVersionNumber;
13 |
14 | //! Project version string for SpecLeaks.
15 | FOUNDATION_EXPORT const unsigned char SpecLeaksVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/SpecLeaksTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SpecLeaksTests/SpecLeaksTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SpecLeaksTests.swift
3 | // SpecLeaksTests
4 | //
5 | // Created by Ruiz, Josué on 5/12/19.
6 | // Copyright © 2019 com.lmp.specleaks. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import SpecLeaks
11 |
12 | class SpecLeaksTests: XCTestCase {
13 |
14 | override func setUp() {
15 | // Put setup code here. This method is called before the invocation of each test method in the class.
16 | }
17 |
18 | override func tearDown() {
19 | // Put teardown code here. This method is called after the invocation of each test method in the class.
20 | }
21 |
22 | func testExample() {
23 | // This is an example of a functional test case.
24 | // Use XCTAssert and related functions to verify your tests produce the correct results.
25 | }
26 |
27 | func testPerformanceExample() {
28 | // This is an example of a performance test case.
29 | self.measure {
30 | // Put the code you want to measure the time of here.
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/_Pods.xcodeproj:
--------------------------------------------------------------------------------
1 | Example/Pods/Pods.xcodeproj
--------------------------------------------------------------------------------
/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leandromperez/specleaks/eff9c85401b5fe380ed0faca216fce18b672e641/twitter.png
--------------------------------------------------------------------------------