Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functions with argument labels gets wrong mock generated. #55

Closed
TadeasKriz opened this issue Aug 31, 2016 · 4 comments
Closed

Functions with argument labels gets wrong mock generated. #55

TadeasKriz opened this issue Aug 31, 2016 · 4 comments

Comments

@TadeasKriz
Copy link
Member

No description provided.

@TadeasKriz
Copy link
Member Author

@krin-san Could you try the commit d8b65f542f6ce2dbcabb58b0b002081d1578b38a? It should be fixed.

@krin-san
Copy link

krin-san commented Sep 1, 2016

@TadeasKriz, the issue with closures now fixed by this commit. However, I catch a few new bugs.

I simplified my real singleton class to smth. like this:

class MyClass {
    static let sharedInstance = MyClass()
    private init() {}
}

The singleton has no fields to initialize (initialization block is empty) but I want to keep initializer private. Unfortunately, this leads to the following error in auto-generated code:

class MockMyClass: MyClass, Cuckoo.Mock {
    typealias Stubbing = __StubbingProxy_MyClass
    typealias Verification = __VerificationProxy_MyClass
    let manager = Cuckoo.MockManager()

    private var observed: MyClass?

// ERROR: Initializer does not override a designated initializer from its superclass
    required override init() {
    }

    ...
}

It's very logical. I should keep the initializer as internal or public to make it mockable - and it works! But let's check another case:

class MyClass {
    var field: String

    init() {
        field = ""
    }
}

I don't want to just leave an empty internal initializer - it's just meaningless. Now this class contains some field that cannot be initialized by default value so I should write my own initialer. This leads to the following issues in auto-generated code:

class MockMyClass: MyClass, Cuckoo.Mock {
    typealias Stubbing = __StubbingProxy_MyClass
    typealias Verification = __VerificationProxy_MyClass
    let manager = Cuckoo.MockManager()

    private var observed: MyClass?

    required override init() {
    }

    required init(spyOn victim: MyClass) {
        observed = victim
    }

    override var field: String {
        get {
            return manager.getter("field", original: observed.map { o in return { () -> String in o.field } })
        }
        set {
            manager.setter("field", value: newValue, original: observed != nil ? { self.observed?.field = $0 } : nil)
        }
    }

    override init() {
        return manager.call("init()", parameters: (), original: observed.map { o in return { () in o.init() } })
    }

    struct __StubbingProxy_MyClass: Cuckoo.StubbingProxy {
        private let manager: Cuckoo.MockManager

        init(manager: Cuckoo.MockManager) {
            self.manager = manager
        }

        var field: Cuckoo.ToBeStubbedProperty<String> {
            return Cuckoo.ToBeStubbedProperty(manager: manager, name: "field")
        }

        @warn_unused_result
// ERROR: Expected identifier in function
        func init() -> Cuckoo.StubNoReturnFunction<()> {
            return Cuckoo.StubNoReturnFunction(stub: manager.createStub("init()", parameterMatchers: []))
        }
    }

    struct __VerificationProxy_MyClass: Cuckoo.VerificationProxy {
        private let manager: Cuckoo.MockManager
        private let callMatcher: Cuckoo.CallMatcher
        private let sourceLocation: Cuckoo.SourceLocation

        init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) {
            self.manager = manager
            self.callMatcher = callMatcher
            self.sourceLocation = sourceLocation
        }

        var field: Cuckoo.VerifyProperty<String> {
            return Cuckoo.VerifyProperty(manager: manager, name: "field", callMatcher: callMatcher, sourceLocation: sourceLocation)
        }

// ERROR: Expected identifier in function
        func init() -> Cuckoo.__DoNotUse<Void> {
            return manager.verify("init()", callMatcher: callMatcher, parameterMatchers: [] as [Cuckoo.ParameterMatcher<Void>], sourceLocation: sourceLocation)
        }
    }
}

The init is not a usual mockable function so the func init syntax is invalid.

@TadeasKriz
Copy link
Member Author

Thank you for the report. The issue with initializers is currently being worked on so hopefully it is something we can fix. Mocking singletons with private initializers cannot be done as you said. Also we cannot return a different type from the singletons sharedInstance property, which means you cannot mock and test against it if your code uses singletons.

@krin-san
Copy link

krin-san commented Sep 1, 2016

As I already mentioned, singleton and private initializer is not an issue. The issues revealed when I tried to make a class testable.
Normally, in a project I use a singleton instance of MyClass but I allocate it as a usual object while testing.

Looks like the key problem of this issue was resolved and the problem I catch related to #54

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants