Giter Site home page Giter Site logo

typealiased / mockingbird Goto Github PK

View Code? Open in Web Editor NEW
648.0 36.0 82.0 27.15 MB

A Swifty mocking framework for Swift and Objective-C.

Home Page: https://mockingbirdswift.com

License: MIT License

Swift 96.10% Ruby 0.11% Shell 0.19% Objective-C 3.60%
swift ocmock ocmockito mock

mockingbird's People

Contributors

ailtonvivaz avatar alvarhansen avatar andrewchang-bird avatar juyan avatar kielgillard avatar marshalgeazipp avatar myihsan avatar paiv avatar peter-nagy avatar rshev avatar ryanmeisters avatar s-hocking avatar shackley avatar ynx-zeissl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mockingbird's Issues

Flattened inherited type is missing rawInheritedTypes

New Issue Checklist

Description

We have case where empty InitializerProxy enum is generated for mock type. This creates mock type that can't be initialized.

The source setup is basically this:

MyVC.swift

import UIKit

class MyVC: UIViewContoller: MyProtocol2 {}

MyProtocol2.swift

protocol MyProtocol2: MyProtocol1 {}

MyProtocol1.swift

import Foundation
protocol MyProtocol1: AnyObject {}

It seems to be caused by ParseFilesOperation excluding dependencies parsing: https://github.com/birdrides/mockingbird/blob/78707c9544d78535e68223e46fabdbb07b1ae3ab/MockingbirdGenerator/Parser/Operations/ParseFilesOperation.swift#L146
&
https://github.com/birdrides/mockingbird/blob/78707c9544d78535e68223e46fabdbb07b1ae3ab/MockingbirdGenerator/Parser/Operations/ParseFilesOperation.swift#L115
which causes flattened inherited types to not find its referenced types if they come from other frameworks.

https://github.com/birdrides/mockingbird/blob/78707c9544d78535e68223e46fabdbb07b1ae3ab/MockingbirdGenerator/Parser/Operations/FlattenInheritanceOperation.swift#L67
referencing search from
https://github.com/birdrides/mockingbird/blob/78707c9544d78535e68223e46fabdbb07b1ae3ab/MockingbirdGenerator/Parser/Operations/FlattenInheritanceOperation.swift#L41

My current workaround hack was to ignore shouldMock flag and parse all files:
https://github.com/birdrides/mockingbird/blob/78707c9544d78535e68223e46fabdbb07b1ae3ab/MockingbirdGenerator/Parser/Operations/ParseFilesOperation.swift#L115
Is there any particular reason why not all files are being parsed? Just optimisation?

Generic typealias in method argument

New Issue Checklist

Description

Generator incorrectly references generic type from inherited protocol.

Generator Bugs

  1. A minimal example of the original source
protocol One {
    typealias Arg<T> = T
    func some<T>(_ x: Arg<T>)
}

class Two : One {
    func some<T>(_ x: Arg<T>) {}
}
  1. The actual mocking code generated
//
//  SampleMocks.generated.swift
//  Sample
//
//  Generated by Mockingbird v0.12.0.
//  DO NOT EDIT
//

@testable import Mockingbird
@testable import Sample
import Foundation
import Swift

private var genericTypesStaticMocks = Mockingbird.Synchronized<[String: Mockingbird.StaticMock]>([:])

// MARK: - Mocked One

public final class OneMock: Sample.One, Mockingbird.Mock {
  static let staticMock = Mockingbird.StaticMock()
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.12.0", "module_name": "Sample"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      OneMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
    Mockingbird.checkVersion(for: self)
    self.sourceLocation = sourceLocation
  }

  // MARK: Mocked `some`<T>(_ `x`: Sample.One.Arg<T>)

  public func `some`<T>(_ `x`: Sample.One.Arg<T>) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`some`<T>(_ `x`: Sample.One.Arg<T>) -> Void", arguments: [Mockingbird.ArgumentMatcher(`x`)])
    mockingContext.didInvoke(invocation) { () -> Void in
      let implementation = stubbingContext.implementation(for: invocation)
      if let concreteImplementation = implementation as? (Sample.One.Arg<T>) -> Void {
        concreteImplementation(`x`)
      } else if let concreteImplementation = implementation as? () -> Void {
        concreteImplementation()
      }
    }
  }

  public func `some`<T>(_ `x`: @escaping @autoclosure () -> Sample.One.Arg<T>) -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Sample.One.Arg<T>) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`x`)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`some`<T>(_ `x`: Sample.One.Arg<T>) -> Void", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Sample.One.Arg<T>) -> Void, Void>(mock: self, invocation: invocation)
  }
}

/// Initialize a protocol mock of `Sample.One`.
public func mock(_ type: Sample.One.Protocol, file: StaticString = #file, line: UInt = #line) -> OneMock {
  return OneMock(sourceLocation: SourceLocation(file, line))
}
  1. The expected mocking code that should be generated (or a description)
// Parameter type here is incorrect:
public func `some`<T>(_ `x`: Sample.One.Arg<T>) -> Void {
//                                      ^
// Type alias 'Arg' can only be used with a concrete type or generic parameter base

// ... and should be
public func `some`<T>(_ `x`: OneMock.Arg<T>) -> Void {

Environment

  • Mockingbird CLI version 0.12.0
  • Xcode 11.4.1 and macOS 10.15.4
  • Swift version Apple Swift version 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51)
  • Installation method CocoaPods

Misinterpreted closure parameter when wrapped in parentheses

New Issue Checklist

Description

Extra parens around closure parameter breaks mocked method.

Generator Bugs

$ mockingbird generate \
  --only-protocols \
  --targets 'Sample' \
  --outputs 'Sample/MockingbirdMocks/SampleMocks.generated.swift'
  1. A minimal example of the original source
protocol One : class {
    func foo(_ x: ((Int) -> Void))
}
  1. The actual mocking code generated
//
//  SampleMocks.generated.swift
//  Sample
//
//  Generated by Mockingbird v0.9.0.
//  DO NOT EDIT
//

@testable import Mockingbird
@testable import Sample
import Foundation
import Swift
import UIKit

private var genericTypesStaticMocks = Mockingbird.Synchronized<[String: Mockingbird.StaticMock]>([:])

// MARK: - Mocked One

public final class OneMock: Sample.One, Mockingbird.Mock {
  static let staticMock = Mockingbird.StaticMock()
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.9.0", "module_name": "Sample"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      OneMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  public enum InitializerProxy {}

  // MARK: Mocked `foo`(_ x: ((Int) -> Void))

  public func `foo`(_ x: ((Int) -> Void)) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ x: ((Int) -> Void)) -> Void", arguments: [Mockingbird.ArgumentMatcher(`x`)])
    mockingContext.didInvoke(invocation)
    let implementation = stubbingContext.implementation(for: invocation, optional: true)
    if let concreteImplementation = implementation as? (((Int) -> Void)) -> Void {
      concreteImplementation(`x`)
    } else {
      (implementation as? () -> Void)?()
    }
  }

  public func `foo`(_ x: @escaping @autoclosure () -> ((Int) -> Void)) -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, (((Int) -> Void)) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`x`)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ x: ((Int) -> Void)) -> Void", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.MethodDeclaration, (((Int) -> Void)) -> Void, Void>(mock: self, invocation: invocation)
  }
}

/// Create a source-attributed `Sample.One` class mock metatype.
public func mock(file: StaticString = #file, line: UInt = #line, _ type: Sample.One.Protocol) -> OneMock.InitializerProxy.Type {
  return OneMock.InitializerProxy.self
}

Compilation error:

SampleMocks.generated.swift:37:134: error: converting non-escaping value to 'T' may allow it to escape
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ x: ((Int) -> Void)) -> Void", arguments: [Mockingbird.ArgumentMatcher(`x`)])
  1. The expected mocking code that should be generated (or a description)
  // MARK: Mocked `foo`(_ x: (Int) -> Void)

  public func `foo`(_ x: (Int) -> Void) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ x: (Int) -> Void) -> Void", arguments: [Mockingbird.ArgumentMatcher(Mockingbird.NonEscapingClosure<(Int) -> Void>())])

Environment

  • Mockingbird CLI version 0.9.0
  • Xcode 11.3.1 and macOS version 10.15.3
  • Swift version Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
  • Installation method CocoaPods

Autogenerated files fail for non-default product name

Description

In the build settings I have changed the 'Product Name' from $(TARGET_NAME) to $(PROJECT_NAME) for reasons outside the scope of this issue. The autogenerated files create 2 issues related to this.

  1. Importing my app creates an issue since the statement says import #target_name# instead of import #project_name#. This issue I was able to resolve by passing --disable-module-import.
  2. All generated classes inherit and conform to something like,
    public class SomeClass: TargetName.SomeClass, MockingBird.Mock,
    which creates the issue of 'this module doesn't exist'.

Since this is a design issue and not a bug, I will leave out code examples unless requested.

Are you able to use the Product Name value from the build settings? By doing this, you would be using the actual value and not assuming the default value, which would fix this problem.

Code signing issue affecting prebuilt CLI binaries 0.9.0 and earlier

Hi, everyone, there’s recently been a code signing issue that affects prebuilt CLI binaries 0.9.0 and earlier. Our recommended fix is to update to version 0.10.0. If you need to remain on 0.9.0 you can also re-download and re-install the 0.9.0 CLI binary from the GitHub releases page.

Apologies if this broke any workflows. Please don’t hesitate to ping me if you need help mitigating this issue.

Override method with generic array argument generated with incorrect type

The generator fails to handle the case where a derived class overrides a method with a generic type in its signature.

Minimal example:

class Concrete {
}

class Base<T> {
    func method(withArg: T) {
    }
}

class Derived: Base<Concrete> {
    override func method(withArg: Concrete) {
    }
}

The generated code this produces:

  // MARK: Mocked `method`(`withArg`: Mocky.Concrete)

  public override func `method`(`withArg`: Mocky.Concrete) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`method`(`withArg`: Mocky.Concrete) -> Void", arguments: [Mockingbird.ArgumentMatcher(`withArg`)])
    mockingContext.didInvoke(invocation) { () -> Void in
      let implementation = stubbingContext.implementation(for: invocation)
      if let concreteImplementation = implementation as? (Mocky.Concrete) -> Void {
        concreteImplementation(`withArg`)
      } else if let concreteImplementation = implementation as? () -> Void {
        concreteImplementation()
      }
    }
  }

  public func `method`(`withArg`: @escaping @autoclosure () -> Mocky.Concrete) -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Mocky.Concrete) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`withArg`)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`method`(`withArg`: Mocky.Concrete) -> Void", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Mocky.Concrete) -> Void, Void>(mock: self, invocation: invocation)
  }

  // MARK: Mocked `method`(`withArg`: Mocky.Concrete)

  public override func `method`(`withArg`: Mocky.Concrete) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`method`(`withArg`: Mocky.Concrete) -> Void", arguments: [Mockingbird.ArgumentMatcher(`withArg`)])
    mockingContext.didInvoke(invocation) { () -> Void in
      let implementation = stubbingContext.implementation(for: invocation)
      if let concreteImplementation = implementation as? (Mocky.Concrete) -> Void {
        concreteImplementation(`withArg`)
      } else if let concreteImplementation = implementation as? () -> Void {
        concreteImplementation()
      }
    }
  }

  public func `method`(`withArg`: @escaping @autoclosure () -> Mocky.Concrete) -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Mocky.Concrete) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`withArg`)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`method`(`withArg`: Mocky.Concrete) -> Void", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Mocky.Concrete) -> Void, Void>(mock: self, invocation: invocation)
  }

Xcode can't compile this because

public override func `method`(`withArg`: Mocky.Concrete) -> Void {

is generated twice and it fails with a method(withArg:) has already been overridden

Environment

  • CLI version: 0.12.0
  • Swift version: 5.2.2
  • Xcode version: 11.4.1
  • Installed via Cocoapods
  • XCTest framework

Private initializer results in inaccessible initializer error in generated code

This example code:

class Concrete {
    private init() {
    }
}

Results in this generated code:

public final class ConcreteMock: Mocky.Concrete, Mockingbird.Mock {

  (...)

  fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
    super.init()
    Mockingbird.checkVersion(for: self)
    self.sourceLocation = sourceLocation
  }
}

Because of the private initializer this results in an 'Concrete' initializer is inaccessible due to 'private' protection level error.

Expected behavior would be compilable generated code. Probably by not creating a mock at all for such classes.

Environment

  • Mockingbird CLI version a246a83 (current master as of this issues creation date)
  • Xcode and macOS version 11.4.1
  • Swift version (Apple Swift version 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51))
  • Installation method CocoaPods

CI setup/automated steps

It seems really strange that the install steps are calling for adding a CLI onto the usr/bin. This seems wayyyy too complicated.

I don't understand why this package can't just be:
// package manager install step
// Run phase script to paste in.

No such module 'Mockingbird'

Description

  1. I installed to my Xcode 11 workspace for my iOS project with File -> Swift Packages -> Add Package Dependency...
  2. Selected my Unit Test target along the way
  3. Seemed to integrate fine
  4. Installed generator from source and ran the Automated Integration steps, seems integrated and mocks are generated automatically
  5. When I try to test, it errors on the first line @testable import Mockingbird in my AppMocks.generated.swift file.

Environment

  • Mockingbird CLI version 0.7.0
  • Xcode 11.1 on macOS Catalina beta (19A582a)

Use without xcode - on purely swift package based projects

New Issue Checklist

Description

The code I talk about is in a draft PR #165
As mocking could be very helpful for projects that do not require you to have an Xcode project I would like to alter the project so I can use it on my server side projects. I'm facing some issues with the way the project is setup.

  • loading the dlib is not working as it is missing the swiftSyntaxParserDylib variable in main
  • just opening the open Package.swift will make xcode resolve the dependencies. This works but then I cannot build because of my first bullet
  • The instructions say you can add Mockingbird to an existing project Package.swift file. But this results in an error if I follow the instructions. dependency 'Mockingbird' in target 'UseCaseInjectTests' requires explicit declaration; provide the name of the package dependency with

To solve this I followed the following steps, unsuccessful so far

  1. I followed the contribution guidelines and ran the make setup-project
  2. Then I cd sources to inspect the package
  3. I tried to add product Mockingbird as a dependency to the commented out test target
  4. added the needed files for a test target
  5. declared swiftSyntaxParserDylib manually as
let file = #file
let dataDlib = file.replacingOccurrences(of: "", with: "") // this is a workaround to be able to build it, not pointing to correct file as this depends on how you build it
let swiftSyntaxParserDylib = Resource(
    encodedData: try Data(contentsOf: URL(fileURLWithPath: dataDlib)).base64EncodedString(),
    fileName: "lib_InternalSwiftSyntaxParser.dylib"
)

This fixed the build and I could import Mockingbird in my added test target.
6. Then I followed the instructions to Manual-Setup

But I lack a bit of background to be able to get this working. What I like to do on Package.swift only projects is:

  • generate the mocks from targets defined in the Package.swift (by default just all except test targets)
  • add some code to a git hook pre-push so it generates the mocks and runs tests before I can push

As this is how I would like to use it without the hassle of having to generate an XCode project I filed this issue. Could you help me get started?

Framework Bugs

Unable to include the Mockingbird framework in a purely swift package project without Xcode.

As this outputs error

dependency 'Mockingbird' in target '<#MyTestTarget#>' requires explicit declaration; provide the name of the package dependency with

Also adding it with .product(name: "Mockingbird", package: "mockingbird") did not do the trick.

Environment

  • Mockingbird CLI version (0.14.0)
  • Xcode and macOS version (11.6)
  • Swift version (5.2)
  • Installation method (SPM)
  • Unit testing framework (XCTest)
  • Are you using supporting source files? Not sure how to, maybe this is the problem that I'm missing something?

Unable to return custom value from function with Void return type

New Issue Checklist

Description

In the README.md, the documentation suggests that a function that returns void like func chirp(volume: Int) should be able to return a custom value like true. I'm not entirely sure of the benefit for returning different types from a function, but this does not currently work.

However, if the intention is to display that an expected return type can be mocked from a function like func chirp(volume: Int) -> Bool, then it works as expected.

Framework Bugs

Please provide a minimal example of your unit testing code, including any errors.

let bird = mock(Bird.self)
given(bird.chirp(volume: 10)) ~> true
// Binary operator '~>' cannot be applied to operands of type 'Stub<(Int) -> Void, Void>' and 'Bool'

Environment

  • Mockingbird CLI version: 0.6.1
  • Xcode and macOS version: Xcode 11.0 (11A420a) - Mojave 10.14.5 Beta
  • Swift version: 5.1
  • Installation method: CocoaPods
  • Unit testing framework: XCTest
  • Does your project use .mockingbird-ignore? No

Stubbing fails on metatype arguments

New Issue Checklist

Description

Stubbing fails on metatype arguments –– matcher compares them by reference.

Framework Bugs

protocol One {
    func foo<T>(_ x: T.Type) -> String
}

extension One {
    func someInt() -> String {
        return foo(Int.self)
    }
}
import XCTest
import Mockingbird
@testable import MockingbirdTestsHost

class MyTests: XCTestCase {

    func testSome() {
        let one = mock(One.self)
        
        given(one.foo(Int.self)) ~> "mocked"
        
        let s = (one as One).someInt()
        
        XCTAssertEqual(s, "mocked")
    }
}
Test Case '-[MockingbirdTests.MyTests testSome]' started.
/mockingbird/MockingbirdTests/Example/MyTests.swift:8: error: -[MockingbirdTests.MyTests testSome] : failed - Missing stubbed implementation for ``foo`<T>(_ x: T.Type) -> String` matching (Int (by reference))
Test Case '-[MockingbirdTests.MyTests testSome]' failed (0.005 seconds).

Environment

  • Mockingbird CLI version 0.9.0
  • Xcode 11.3.1 and macOS version 10.15.3
  • Swift version Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
  • Installation method CocoaPods

Missing inOrder verification

New Issue Checklist

Description

Verification needs a way to check the order of invoked mocks.

For example,

protocol Some {
    func foo()
    func bar()
}

func example(_ some: Some) {
    some.bar()
    some.foo()
}
func test_example() {
    let some = mock(Some.self)
    let inOrder = inOrder(some)
    
    example(some)

    // failing
    // inOrder.verify(some.foo()).wasCalled(once)
    // inOrder.verify(some.bar()).wasCalled(once)

    // passing
    inOrder.verify(some.bar()).wasCalled(once)
    inOrder.verify(some.foo()).wasCalled(once)
}

Environment

  • Mockingbird CLI version 0.9.0
  • Xcode 11.3.1 macOS version 10.15.3
  • Swift version Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
  • Installation method CocoaPods

EXC_BAD_ACCESS on Argument Matcher with Protocol

New Issue Checklist

Description

When using an argument matcher on a protocol that is implemented by a struct the test crashes with EXC_BAD_ACCESS. See thread backtrace below.

Framework Bug

App code

protocol MyStructProtocol {}
struct MyStructImpl : MyStructProtocol {}

class MyService {
    func handle(myStruct: MyStructProtocol) {}
}

class MyRepository {
    var service: MyService
    init(service: MyService) {
        self.service = service
    }

    func callService() {
        self.service.handle(myStruct: MyStructImpl())
    }
}

Test code

import XCTest
import Mockingbird
@testable import mockingbird_bug_report

class MyRepositoryTest: XCTestCase {
    public var subject: MyRepository!
    var service: MyServiceMock!

    func testExample() {
        service = mock(MyService.self)
        subject = MyRepository(service: service)
        subject.callService()
        verify(service.handle(myStruct: any())).wasCalled()
    }
}

Thread backtrace

* thread #1, queue = 'co.bird.mockingbird.typefacade', stop reason = EXC_BAD_ACCESS (code=1, address=0xfffffffffffffff8)
    frame #0: 0x00007fff50b563cd libswiftCore.dylib`swift::metadataimpl::ValueWitnesses<swift::metadataimpl::OpaqueExistentialBox<1u> >::initializeWithCopy(swift::OpaqueValue*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*) + 29
  * frame #1: 0x0000000103e55cdf Mockingbird`createTypeFacade<T>(value=0x0000600001154d00) at TypeFacade.swift:44:70
    frame #2: 0x0000000103e40f54 Mockingbird`any<T>(type=mockingbird_bug_report.MyStructProtocol) at Mockingbird.swift:95:10
    frame #3: 0x0000000103dfdeed mockingbird-bug-reportTests`implicit closure #1 in MyRepositoryTest.testExample() at <compiler-generated>:0
    frame #4: 0x0000000103e56494 Mockingbird`closure #1 in resolve<T>(parameter=0x0000000103dfdeb0 mockingbird-bug-reportTests`implicit closure #1 () -> mockingbird_bug_report.MyStructProtocol in mockingbird_bug_reportTests.MyRepositoryTest.testExample() -> () at <compiler-generated>, storedValue=0x0000600002ad3000, resolvedMatcher=nil) at TypeFacade.swift:54:21
    frame #5: 0x0000000103e5685c Mockingbird`thunk for @callee_guaranteed () -> () at <compiler-generated>:0
    frame #6: 0x0000000103e568c1 Mockingbird`thunk for @escaping @callee_guaranteed () -> () at <compiler-generated>:0
    frame #7: 0x00007fff511fc7f9 libdispatch.dylib`_dispatch_client_callout + 8
    frame #8: 0x00007fff512097ff libdispatch.dylib`_dispatch_lane_barrier_sync_invoke_and_complete + 94
    frame #9: 0x0000000103e5607c Mockingbird`resolve<T>(parameter=0x0000000103dfdeb0 mockingbird-bug-reportTests`implicit closure #1 () -> mockingbird_bug_report.MyStructProtocol in mockingbird_bug_reportTests.MyRepositoryTest.testExample() -> () at <compiler-generated>) at TypeFacade.swift:53:9
    frame #10: 0x0000000103df2159 mockingbird-bug-reportTests`MyServiceMock.handle(myStruct=0x0000000103dfdeb0 mockingbird-bug-reportTests`implicit closure #1 () -> mockingbird_bug_report.MyStructProtocol in mockingbird_bug_reportTests.MyRepositoryTest.testExample() -> () at <compiler-generated>, self=0x0000600003108600) at mockingbird_bug_reportMocks.generated.swift:219:53
    frame #11: 0x0000000103dfdc45 mockingbird-bug-reportTests`MyRepositoryTest.testExample(self=0x0000600003139e60) at mockingbird_bug_reportTests.swift:13:24
    frame #12: 0x0000000103dfe0eb mockingbird-bug-reportTests`@objc MyRepositoryTest.testExample() at <compiler-generated>:0
    frame #13: 0x00007fff23b9f95c CoreFoundation`__invoking___ + 140
    frame #14: 0x00007fff23b9cd8f CoreFoundation`-[NSInvocation invoke] + 287
    frame #15: 0x0000000103b09121 XCTest`__24-[XCTestCase invokeTest]_block_invoke.208 + 78
    frame #16: 0x0000000103b631e2 XCTest`-[XCTestCase(Failures) performFailableBlock:testCaseRun:shouldInterruptTest:] + 57
    frame #17: 0x0000000103b63100 XCTest`-[XCTestCase(Failures) _performTurningExceptionsIntoFailuresInterruptAfterHandling:block:] + 96
    frame #18: 0x0000000103b08c0a XCTest`__24-[XCTestCase invokeTest]_block_invoke + 1153
    frame #19: 0x0000000103b086e2 XCTest`-[XCTestCase testContextPerformInScope:] + 211
    frame #20: 0x0000000103b0877c XCTest`-[XCTestCase invokeTest] + 137
    frame #21: 0x0000000103b0a4ed XCTest`__26-[XCTestCase performTest:]_block_invoke_2 + 43
    frame #22: 0x0000000103b631e2 XCTest`-[XCTestCase(Failures) performFailableBlock:testCaseRun:shouldInterruptTest:] + 57
    frame #23: 0x0000000103b63100 XCTest`-[XCTestCase(Failures) _performTurningExceptionsIntoFailuresInterruptAfterHandling:block:] + 96
    frame #24: 0x0000000103b0a404 XCTest`__26-[XCTestCase performTest:]_block_invoke.334 + 88
    frame #25: 0x0000000103b76492 XCTest`+[XCTContext runInContextForTestCase:block:] + 219
    frame #26: 0x0000000103b09b73 XCTest`-[XCTestCase performTest:] + 668
    frame #27: 0x0000000103b4f077 XCTest`-[XCTest runTest] + 57
    frame #28: 0x0000000103b0414a XCTest`__27-[XCTestSuite performTest:]_block_invoke + 365
    frame #29: 0x0000000103b03874 XCTest`-[XCTestSuite _performProtectedSectionForTest:testSection:] + 54
    frame #30: 0x0000000103b03b71 XCTest`-[XCTestSuite performTest:] + 355
    frame #31: 0x0000000103b4f077 XCTest`-[XCTest runTest] + 57
    frame #32: 0x0000000103b0414a XCTest`__27-[XCTestSuite performTest:]_block_invoke + 365
    frame #33: 0x0000000103b03874 XCTest`-[XCTestSuite _performProtectedSectionForTest:testSection:] + 54
    frame #34: 0x0000000103b03b71 XCTest`-[XCTestSuite performTest:] + 355
    frame #35: 0x0000000103b4f077 XCTest`-[XCTest runTest] + 57
    frame #36: 0x0000000103b0414a XCTest`__27-[XCTestSuite performTest:]_block_invoke + 365
    frame #37: 0x0000000103b03874 XCTest`-[XCTestSuite _performProtectedSectionForTest:testSection:] + 54
    frame #38: 0x0000000103b03b71 XCTest`-[XCTestSuite performTest:] + 355
    frame #39: 0x0000000103b4f077 XCTest`-[XCTest runTest] + 57
    frame #40: 0x0000000103b8543e XCTest`__44-[XCTTestRunSession runTestsAndReturnError:]_block_invoke + 171
    frame #41: 0x0000000103b85541 XCTest`__44-[XCTTestRunSession runTestsAndReturnError:]_block_invoke.84 + 118
    frame #42: 0x0000000103b1de83 XCTest`-[XCTestObservationCenter _observeTestExecutionForBlock:] + 588
    frame #43: 0x0000000103b851fd XCTest`-[XCTTestRunSession runTestsAndReturnError:] + 623
    frame #44: 0x0000000103ae76d7 XCTest`-[XCTestDriver runTestsAndReturnError:] + 456
    frame #45: 0x0000000103b726e4 XCTest`_XCTestMain + 2484
    frame #46: 0x00000001038adbe7 libXCTestBundleInject.dylib`__RunTests_block_invoke_2 + 13
    frame #47: 0x00007fff23afb8ec CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    frame #48: 0x00007fff23afb058 CoreFoundation`__CFRunLoopDoBlocks + 312
    frame #49: 0x00007fff23af5ebe CoreFoundation`__CFRunLoopRun + 1246
    frame #50: 0x00007fff23af56b6 CoreFoundation`CFRunLoopRunSpecific + 438
    frame #51: 0x00007fff3815cbb0 GraphicsServices`GSEventRunModal + 65
    frame #52: 0x00007fff47162a67 UIKitCore`UIApplicationMain + 1621
    frame #53: 0x00000001037ef8fb mockingbird-bug-report`main at AppDelegate.swift:12:7
    frame #54: 0x00007fff5123bcf5 libdyld.dylib`start + 1
    frame #55: 0x00007fff5123bcf5 libdyld.dylib`start + 1

Podfile

target 'mockingbird-bug-report' do
  use_frameworks!
  target 'mockingbird-bug-reportTests' do
    inherit! :search_paths
    pod "MockingbirdFramework"
  end
end

Environment

  • Mockingbird CLI version (mockingbird version) 0.9.0
  • Xcode and macOS version (are you running a beta?) Xcode Version 11.0 (11A420a), macOS Catalina 10.15.2 (19C57)
  • Swift version (swift --version) Apple Swift version 5.1 (swiftlang-1100.0.270.13 clang-1100.0.33.7)
    Target: x86_64-apple-darwin19.2.0
  • Installation method (CocoaPods, Carthage, from source, etc) CocoaPods
  • Unit testing framework (XCTest, Quick + Nimble, etc) XCTest
  • Does your project use .mockingbird-ignore? No

Unable get generate file

can you guide me install and generating mock file. I have it tried by below way.
My Used file as below.
Protocol -> LoginProtocol
Manager -> LoginApiManager
TestFile -> LoginTests
project target -> Login
test target -> LoginTest

// Below command generate blur file of generated mocs but cant accessible in project

mockingbird install
--project Login.xcodeproj
--target LoginExample
--destination LoginTests

Can you guide me how to generate LoginProtocol mocs .

dyld: lazy symbol binding failed: can't resolve symbol _swiftparse_syntax_structure_versioning_identifier?

New Issue Checklist

Description

We're getting the following error on CI, running our tests against a simulator (but not locally):

/bin/sh -c /Users/runner/work/1/output/test/build.obj/XXXX.build/Dev-iphonesimulator/XXXXTests.build/Script-D2484978880008EAC85DCA93.sh
dyld: lazy symbol binding failed: can't resolve symbol _swiftparse_syntax_structure_versioning_identifier in /Users/runner/work/1/s/Pods/MockingbirdFramework/mockingbird because dependent dylib #3 could not be loaded
dyld: can't resolve symbol _swiftparse_syntax_structure_versioning_identifier in /Users/runner/work/1/s/Pods/MockingbirdFramework/mockingbird because dependent dylib #3 could not be loaded
/Users/runner/work/1/output/test/build.obj/XXXX.build/Dev-iphonesimulator/XXXXTests.build/Script-D2484978880008EAC85DCA93.sh: line 7:  8902 Abort trap: 6           ${SRCROOT}/Pods/MockingbirdFramework/mockingbird generate --targets 'XXXX' 'XXXXCore' --outputs "${SRCROOT}/MockingbirdMocks/XXXXTests-XXXXMocks.generated.swift" "${SRCROOT}/MockingbirdMocks/XXXXTests-XXXXCoreMocks.generated.swift" --support "${SRCROOT}/MockingbirdSupport"
Command PhaseScriptExecution failed with a nonzero exit code

Environment

  • Mockingbird CLI version (mockingbird version) 0.16.0
  • Xcode and macOS version (are you running a beta?) 11.7, 10.15.7
  • Swift version (swift --version) Apple Swift version 5.2.4 (swiftlang-1103.0.32.9 clang-1103.0.32.53)
  • Installation method (CocoaPods, Carthage, from source, etc) CocoaPods
  • Unit testing framework (XCTest, Quick + Nimble, etc) XCTest
  • Does your project use .mockingbird-ignore? No
  • Are you using supporting source files? No

(To be fair this could be a problem with Mockingbird, AppCenter, CocoaPods or Xcode or something in our project specifically, just wanted to see if anyone had come across it or anything similar before.)

Installation with CocoaPods

Can't install the framework with CocoaPods. During the installation process "pod install" error below is received.

[!] CDN: trunk Repo update failed - 7 error(s): CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.10.0/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.11.0/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.6.0/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.6.1/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.7.0/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.8.0/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.9.0/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK

Failing to infer mocked type

New Issue Checklist

Description

Inferred return type of mock() is not usable.

Generator Bugs

$ mockingbird generate \
--only-protocols \
--disable-cache \
--targets 'Sample' \
--outputs "${SRCROOT}/MockingbirdMocks/SampleMocks.generated.swift"
  1. A minimal example of the original source
protocol Bird {
  func fly()
}
  1. The actual mocking code generated
//
//  SampleMocks.generated.swift
//  Sample
//
//  Generated by Mockingbird v0.11.0.
//  DO NOT EDIT
//

@testable import Mockingbird
@testable import Sample
import Foundation
import Swift

private var genericTypesStaticMocks = Mockingbird.Synchronized<[String: Mockingbird.StaticMock]>([:])

// MARK: - Mocked Bird

public final class BirdMock: Sample.Bird, Mockingbird.Mock, BirdAbstractMockType {
  static let staticMock = Mockingbird.StaticMock()
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.11.0", "module_name": "Sample"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      BirdMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
    Mockingbird.checkVersion(for: self)
    self.sourceLocation = sourceLocation
  }

  // MARK: Mocked `fly`()

  public func `fly`() -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`fly`() -> Void", arguments: [])
    mockingContext.didInvoke(invocation)
    let implementation = stubbingContext.implementation(for: invocation, optional: true)
    if let concreteImplementation = implementation as? () -> Void {
      concreteImplementation()
    } else {
      (implementation as? () -> Void)?()
    }
  }

  public func `fly`() -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, () -> Void, Void> {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`fly`() -> Void", arguments: [])
    return Mockingbird.Mockable<Mockingbird.MethodDeclaration, () -> Void, Void>(mock: self, invocation: invocation)
  }
}

public protocol BirdAbstractMockType {}

/// Initialize a protocol mock of `Sample.Bird`.
public func mock(_ type: Sample.Bird.Protocol, file: StaticString = #file, line: UInt = #line) -> BirdAbstractMockType {
  return BirdMock(sourceLocation: SourceLocation(file, line))
}

/// Initialize a protocol mock of `Sample.Bird`.
public func mock<__ReturnType: BirdAbstractMockType>(_ type: Sample.Bird.Protocol, file: StaticString = #file, line: UInt = #line) -> __ReturnType {
  return BirdMock(sourceLocation: SourceLocation(file, line)) as! __ReturnType
}

/// Create a dummy object of `Sample.Bird`.
public func dummy(_ type: Sample.Bird.Protocol, file: StaticString = #file, line: UInt = #line) -> BirdMock {
  return BirdMock(sourceLocation: SourceLocation(file, line))
}

/// Initialize a protocol mock of `Sample.Bird`.
@available(swift, obsoleted: 3.0, renamed: "dummy", message: "Store the mock in a variable of type 'BirdMock' or use 'dummy(Bird.self)' to create a non-mockable dummy object")
public func mock<__ReturnType>(_ type: Sample.Bird.Protocol) -> __ReturnType { fatalError() }
  1. The expected mocking code that should be generated (or a description)

Not sure yet.

Framework Bugs

Please provide a minimal example of your unit testing code, including any errors.

func testBird() {
    let bird = mock(Bird.self)

    (bird as Bird).fly()
    // 'BirdAbstractMockType' is not convertible to 'Bird'; did you mean to use 'as!' to force downcast?

    verify(bird.fly()).wasCalled()
    // Value of type 'BirdAbstractMockType' has no member 'fly'
}

Environment

  • Mockingbird CLI version 0.11.0
  • Xcode 11.4 and macOS 10.15.4
  • Swift version Apple Swift version 5.2 (swiftlang-1103.0.32.1 clang-1103.0.32.29)
  • Installation method CocoaPods

Missing subscript support

New Issue Checklist

Description

Generator skips subscript in a protocol.

Generator Bugs

$ mockingbird generate \
  --only-protocols \
  --targets 'Sample' \
  --outputs 'Sample/MockingbirdMocks/SampleMocks.generated.swift'
  1. A minimal example of the original source
protocol Third {
    subscript(index: String) -> String? { get set }
}
  1. The actual mocking code generated
// MARK: - Mocked Third

public final class ThirdMock: Sample.Third, Mockingbird.Mock {
  static let staticMock = Mockingbird.StaticMock()
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.9.0", "module_name": "Sample"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      ThirdMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
    Mockingbird.checkVersion(for: self)
    self.sourceLocation = sourceLocation
  }
}

/// Create a source-attributed `Sample.Third` concrete protocol mock instance.
public func mock(file: StaticString = #file, line: UInt = #line, _ type: Sample.Third.Protocol) -> ThirdMock {
  return ThirdMock(sourceLocation: SourceLocation(file, line))
}
  1. The expected mocking code that should be generated (or a description)

Similar to properties, something along the lines:

// MARK: Mocked subscript(index: String) -> String?

public subscript(`index`: String) -> String? {
    get {
        let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "subscript.get(_ index: String) -> String?", arguments: [Mockingbird.ArgumentMatcher(`index`)])
        mockingContext.didInvoke(invocation)
        let implementation = stubbingContext.implementation(for: invocation, optional: false)
        if let concreteImplementation = implementation as? (String) -> String? {
          return concreteImplementation(`index`)
        } else {
          return (implementation as! () -> String?)()
        }
    }
    set {
        let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "subscript.set(_ index: String, _ newValue: String?) -> Void", arguments: [ArgumentMatcher(`index`), ArgumentMatcher(newValue)])
        mockingContext.didInvoke(invocation)
        let implementation = stubbingContext.implementation(for: invocation, optional: true)
        if let concreteImplementation = implementation as? (String, String?) -> Void {
          concreteImplementation(`index`, newValue)
        } else {
          (implementation as? () -> Void)?()
        }
    }
}

public func subscriptGet(_ `index`: @escaping @autoclosure () -> String) -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, (String) -> String?, String?> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`index`)]
  let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "subscript.get(_ index: String) -> String?", arguments: arguments)
  return Mockingbird.Mockable<Mockingbird.MethodDeclaration, (String) -> String?, String?>(mock: self, invocation: invocation)
}

public func subscriptSet(_ `index`: @escaping @autoclosure () -> String, _ newValue: @escaping @autoclosure () -> String?) -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, (String, String?) -> Void, Void> {
  let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`index`), Mockingbird.resolve(`newValue`)]
  let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "subscript.set(_ index: String, _ newValue: String?) -> Void", arguments: arguments)
  return Mockingbird.Mockable<Mockingbird.MethodDeclaration, (String, String?) -> Void, Void>(mock: self, invocation: invocation)
}

Environment

  • Mockingbird CLI version 0.9.0
  • Xcode 11.3.1 macOS version 10.15.3
  • Swift version Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
  • Installation method CocoaPods

'required' initializer 'init(from:)' must be provided by subclass of 'Car'

New Issue Checklist

  • [x ] I updated my Mockingbird framework and CLI to the latest version
  • [x ] I searched for existing GitHub issues

Description

A simple class like this produces this error:

'required' initializer 'init(from:)' must be provided by subclass of 'Car'

public class Car: Codable {
    
    private var brand: String
    
    public init(brand: String) {
        self.brand = brand
    }
}

Generator Bugs

Please provide the complete output when running Mockingbird CLI, including any options used.

I executed the line below once and to run the tests I press ⌘ + U which seems to generate a new mocking file each time.

$ mockingbird install --target Car --destination CarTests

If the generator produces code that is malformed or does not compile, please provide:

  1. A minimal example of the original source
public class Car: Codable {
    
    private var brand: String
    
    public init(brand: String) {
        self.brand = brand
    }
}
  1. The actual mocking code generated
public final class CarMock: Binfinder.Car, Mockingbird.Mock {
  static let staticMock = Mockingbird.StaticMock()
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.10.0", "module_name": "Binfinder"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      CarMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  public enum InitializerProxy {
    public static func initialize(`brand`: String, __file: StaticString = #file, __line: UInt = #line) -> CarMock {
      let mock: CarMock = CarMock(brand: `brand`)
      mock.sourceLocation = SourceLocation(__file, __line)
      return mock
    }
  }

  // MARK: Mocked init(`brand`: String)

  public required override init(`brand`: String) {
    super.init(brand: `brand`)
    Mockingbird.checkVersion(for: self)
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "init(`brand`: String) ", arguments: [Mockingbird.ArgumentMatcher(`brand`)])
    mockingContext.didInvoke(invocation)
  }
}
  1. The expected mocking code that should be generated (or a description)
public final class CarMock: Binfinder.Car, Mockingbird.Mock {
  static let staticMock = Mockingbird.StaticMock()
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.10.0", "module_name": "Binfinder"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      CarMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  public enum InitializerProxy {
    public static func initialize(`brand`: String, __file: StaticString = #file, __line: UInt = #line) -> CarMock {
      let mock: CarMock = CarMock(brand: `brand`)
      mock.sourceLocation = SourceLocation(__file, __line)
      return mock
    }
  }

  // MARK: Mocked init(`brand`: String)

  public required override init(`brand`: String) {
    super.init(brand: `brand`)
    Mockingbird.checkVersion(for: self)
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "init(`brand`: String) ", arguments: [Mockingbird.ArgumentMatcher(`brand`)])
    mockingContext.didInvoke(invocation)
  }
    
    required init(from decoder: Decoder) throws {
        fatalError("init(from:) has not been implemented")
    }
}

Environment

  • Mockingbird CLI version: 0.10.0
  • Xcode: 11.4 (11E146) and macOS 10.15.4 (19E287)
  • Swift version 5.2 (swiftlang-1103.0.32.1 clang-1103.0.32.29)
  • Installation method: SPM
  • Unit testing framework: XCTest
  • Does your project use .mockingbird-ignore? No

Ambiguous use of operator '~>' while stubbing methods without parameter

New Issue Checklist

Description

The Ambiguous use of operator '~>' error pops up while stubbing methods without parameter using a closure.

Framework Bugs

Bird.swift

import Foundation

public protocol Bird {
  func fly()
}

BirdTests.swift

class TreeTests: XCTestCase {

  var bird: BirdMock!

  override func setUp() {
    bird = mock(Bird.self)
  }

  func testStubFly() {
    given(bird.fly()) ~> { print("fly") } // ⚠️ Ambiguous use of operator '~>'
  }
}

I think it matches these two methods.

public func ~> <I, R>(stub: Stub<I, R>, implementation: @escaping () -> R) {
  addStub(stub, implementation: implementation)
}

public func ~> <I, R>(stub: Stub<I, R>, implementation: I) {
  addStub(stub, implementation: implementation)
}

Environment

  • Mockingbird CLI version 0.11.0
  • Xcode 11.4 and macOS version 10.15.4
  • Swift version Apple Swift version 5.2 (swiftlang-1103.0.32.1 clang-1103.0.32.29)
  • Installation method CocoaPods
  • Unit testing framework XCTest
  • Does your project use .mockingbird-ignore? No

Generated code of a generic type is always in the form of thunk stubs

New Issue Checklist

Description

When we mocking a generic type:

mock(SomeGenericTypeMock<Int>.self)

The name we are using to mock–"SomeGenericTypeMock<Int>" is not equal to the name of the original type name–"SomeGenericType<T>", so Mockingbird can't detect that we are mocking this type.

Proposal

#154 may solve the Mock part.
For the type placeholders part, we may have to erase them before checking the name.

if mockableType.requiresGenericInitializer {
    guard let regex = try? NSRegularExpression(pattern: "<.*>") else { return true }
    let comparableTypeName: (String) -> String = { typeName in
        let comparableTypeName = NSMutableString(string: typeName)
        regex.replaceMatches(in: comparableTypeName, range: NSRange(location: 0, length: typeName.count), withTemplate: "")
        return comparableTypeName as String
    }
    let comparableTypeNames = typeNames.map(comparableTypeName)
    return comparableTypeNames.contains(comparableTypeName(mockableType.fullyQualifiedName)) ||
        comparableTypeNames.contains(comparableTypeName(mockableType.fullyQualifiedModuleName))
} else {
    return typeNames.contains(mockableType.fullyQualifiedName) ||
        typeNames.contains(mockableType.fullyQualifiedModuleName)
}

Guide on mocking static methods

I see in Readme that mockingbird supports mocking static members.
Can you provide any sample on how to mock a static method of a class?

Thanks

Codable - 'required' initializer 'init(from:)' must be provided by subclass

New Issue Checklist

Description

Mockingbird generates code that fails to compile when models that comply to Codable are involved.
Might be related to #87, as the error is the same, though that applied to Decodable. I can confirm Encodable alone compiles properly, just not both together.

The error shown from the example below:
'required' initializer 'init(from:)' must be provided by subclass of 'CodModel'

And the Xcode suggested hotfix is:

Insert '
  required init(from decoder: Decoder) throws {
      fatalError("init(from:) has not been implemented")
  }
'
  1. A minimal example of the original source
Click to expand example code
    public class CodModel: Codable {
        enum CodingKeys: String, CodingKey {
            case name
        }
        
        public var name: String
    
        public init(name: String) {
            self.name = name
        }
        
    }
  1. The actual mocking code generated
Click to expand generated code
    @testable import Mockingbird
    @testable import MockingbirdTesting
    import Foundation
    import Swift
    
    private var genericTypesStaticMocks = Mockingbird.Synchronized<[String: Mockingbird.StaticMock]>([:])
    
    // MARK: - Mocked CodModel
    
    public final class CodModelMock: MockingbirdTesting.CodModel, Mockingbird.Mock {
      static let staticMock = Mockingbird.StaticMock()
      public let mockingContext = Mockingbird.MockingContext()
      public let stubbingContext = Mockingbird.StubbingContext()
      public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.12.2", "module_name": "MockingbirdTesting"])
      public var sourceLocation: Mockingbird.SourceLocation? {
        get { return stubbingContext.sourceLocation }
        set {
          stubbingContext.sourceLocation = newValue
          CodModelMock.staticMock.stubbingContext.sourceLocation = newValue
        }
      }
    
      public enum InitializerProxy {
        public static func initialize(`name`: String, __file: StaticString = #file, __line: UInt = #line) -> CodModelMock {
          let mock: CodModelMock = CodModelMock(name: `name`)
          mock.sourceLocation = SourceLocation(__file, __line)
          return mock
        }
      }
    
      // MARK: Mocked name
    
      override public var `name`: String {
        get {
          let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "name.get", arguments: [])
          return mockingContext.didInvoke(invocation) { () -> String in
            let implementation = stubbingContext.implementation(for: invocation)
            if let concreteImplementation = implementation as? () -> String {
              return concreteImplementation()
            } else if let defaultValue = stubbingContext.defaultValueProvider.provideValue(for: (String).self) {
              return defaultValue
            } else {
              fatalError(stubbingContext.failTest(for: invocation))
            }
          }
        }
        set {
          let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "name.set", arguments: [ArgumentMatcher(newValue)])
          mockingContext.didInvoke(invocation)
          let implementation = stubbingContext.implementation(for: invocation)
          if let concreteImplementation = implementation as? (String) -> Void {
            concreteImplementation(newValue)
          } else {
            (implementation as? () -> Void)?()
          }
        }
      }
    
      public func getName() -> Mockingbird.Mockable<Mockingbird.VariableDeclaration, () -> String, String> {
        let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "name.get", arguments: [])
        return Mockingbird.Mockable<Mockingbird.VariableDeclaration, () -> String, String>(mock: self, invocation: invocation)
      }
    
      public func setName(_ newValue: @escaping @autoclosure () -> String) -> Mockingbird.Mockable<Mockingbird.VariableDeclaration, (String) -> Void, Void> {
        let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(newValue)]
        let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "name.set", arguments: arguments)
        return Mockingbird.Mockable<Mockingbird.VariableDeclaration, (String) -> Void, Void>(mock: self, invocation: invocation)
      }
    
      // MARK: Mocked init(`name`: String)
    
      public required override init(`name`: String) {
        super.init(name: `name`)
        Mockingbird.checkVersion(for: self)
        let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "init(`name`: String) ", arguments: [Mockingbird.ArgumentMatcher(`name`)])
        mockingContext.didInvoke(invocation)
      }
    }
    
    /// Initialize an initializable class mock of `MockingbirdTesting.CodModel`.
    public func mock(_ type: MockingbirdTesting.CodModel.Type, file: StaticString = #file, line: UInt = #line) -> CodModelMock.InitializerProxy.Type {
      return CodModelMock.InitializerProxy.self
    }

Environment

  • Mockingbird CLI version (mockingbird version) 0.12.2
  • Xcode and macOS version (are you running a beta?) 11.3.1
  • Swift version (swift --version) 5.1.3
  • Installation method (CocoaPods, Carthage, from source, etc) CocoaPods
  • Unit testing framework (XCTest, Quick + Nimble, etc) XCTest
  • Does your project use .mockingbird-ignore? No
  • Are you using supporting source files? No

Unconsolidated parameter type for mock initialization

New Issue Checklist

Description

When mocking non-generic types:

mock(SomeType.self)

When mocking generic types:

mock(SomeTypeMock<Int>.self)

And this difference seems undocumented.

Proposal

For a non-protocol generic type:

public func mock<T>(_ type: ModelName.SomeGenericClass<T>.Type, file: StaticString = #file, line: UInt = #line) -> SomeGenericClassMock<T>

It's alright to code this way for a non-protocol generic type. But we can't do the same thing for an associated type required protocol. Luckily, there is a tricky way to solve this problem.

enum AssociatedTypesRequiredProtocol<T> {}
public func mock<T>(_ type: AssociatedTypesRequiredProtocol<T>.Type, file: StaticString = #file, line: UInt = #line) -> AssociatedTypesRequiredProtocolMock<T>

But it may seem odd in Swift when a user codes something like below:

mock(SomeProtocol<Int>.self)

Unable to use the `.mockingbird-ignore` file to blacklist all files and whitelist specific files that are more than 1 folder deep

New Issue Checklist

Description

When using the .mockingbird-ignore file I'm unable to include files by using the ! that are more than 1 folder deep in my project when I've blacklisted all files.

I have a .mockingbird-ignore file that I want to use by blacklisting all files and only whitelisting the ones that I want to Mock. Below I've outlined the file to show which statements work and which do not. Not sure if this is a known limitation?

If I remove all lines from the .mockingbird-ignore then it properly parses the files that are more than 1 folder deep so I can confirm that it generates the mocks on the files that are being whitelisted below when there are no files listed in the .mockingbird-ignore

# Blacklist all files/folders
*

# Whitelist some files
# works
!File1.swift
!File2.swift
!folder1/File3.swift
!folder1/*.swift

# Doesn't work
!folder1/folder2/File4.swift
!folder1/folder3/*.swift

Environment

  • Mockingbird CLI version (mockingbird version)
    0.16.0

  • Xcode and macOS version (are you running a beta?)
    MacOS Catalina 10.15.7
    Xcode 12.2

  • Swift version (swift --version)
    Apple Swift version 5.3.1 (wiftlang-1200.0.41 clang-1200.0.32.8)
    Target: x86_64-apple-darwin19.6.0

  • Installation method (CocoaPods, Carthage, from source, etc)
    Cocoapods

  • Unit testing framework (XCTest, Quick + Nimble, etc)
    Quick + Nimble

  • Does your project use .mockingbird-ignore?
    Yes

  • Are you using supporting source files?
    No

Cannot verify .wasCalled()

New Issue Checklist

Description

When using a mocked object, calling a method that is defined in the protocol throws a compile error. Using the Bird protocol that is provided in the example, the BirdMock object should be able to call chirp(volume:).

If this is expected behavior (not being able to call methods on mocked objects), how would a user verify wasCalled() on the method. Wrapping the call in either given or verify still do not produce a success on wasCalled whether it's on the same line, different line, or second call.

I believe the expected behavior is to create the mock object, be able to call the function of a mocked object, then check if that function was called (passing in the exact same parameters) in a verify statement.

In conclusion, wasNeverCalled() seems to always succeed no matter what I tried when working with methods defined in a protocol.

Framework Bugs

Please provide a minimal example of your unit testing code, including any errors.

Expected this to work:

let bird = mock(Bird.self)
bird.chirp(volume: 10)
// 🛑 Ambiguous use of 'chirp(volume:)'

Tried this from documentation:

let bird = mock(Bird.self)
verify(bird.chirp(volume: 50)).wasCalled()
// 🛑 failed - Incorrect total invocations of `chirp(volume: Int) -> Void` matching (50)
	expected `0` = 1

wasNeverCalled() always succeeds

let bird = mock(Bird.self)
verify(bird.chirp(volume: 50)) //⚠️ Result of call to 'verify(file:line:_:)' is unused
verify(bird.chirp(volume: 50)).wasNeverCalled()
// ✅

Environment

  • Mockingbird CLI version (mockingbird version) => 0.6.1
  • Xcode and macOS version (are you running a beta?) => Xcode 11.0 (11A420a) - Mojave 10.14.5 Beta
  • Swift version (swift --version) => 5.1
  • Installation method (CocoaPods, Carthage, from source, etc) => CocoaPods
  • Unit testing framework (XCTest, Quick + Nimble, etc) => XCTest
  • Does your project use .mockingbird-ignore? => no

Mocked targets with dashes do not compile

New Issue Checklist

Description

If you mock a target with a dash in its name, such as “TestTarget-iOS”, the generated mocks from Mockingbird will not compile.

This is because targets with dashes must be imported and accessed with an underscore instead.
e.g. “import TestTarget_iOS”

$ mockingbird install —targets App-iOS —destination App-iOSTests
Installed Mockingbird to `App-iOSTests` in /Users/daedren/git/appiOS/appiOS.xcodeproj

Environment

  • Mockingbird CLI version (mockingbird version)
    0.7.0
  • Xcode and macOS version (are you running a beta?)
    Xcode 11.1
    macOS 10.14.4
  • Swift version (swift --version)
    Swift 5.1
  • Installation method (CocoaPods, Carthage, from source, etc)
    CocoaPods
  • Unit testing framework (XCTest, Quick + Nimble, etc)
    XCTest
  • Does your project use .mockingbird-ignore?
    It does not

Invalid Redeclaration error when dealing with protocols that support variadics

New Issue Checklist

Description

Protocols with overloaded functions with a variadic signature and an input array signature leads to redeclarations in the generated code.

Generator Bugs

If the generator produces code that is malformed or does not compile, please provide:

  1. A minimal example of the original source
public protocol HashidsGenerator {
    associatedtype Char

    func encode64(_ value: Int64...) -> String?

    func encode64(_ values: [Int64]) -> String?
}
  1. The actual mocking code generated
public final class HashidsGeneratorMock<Char>: Backbone.HashidsGenerator, Mockingbird.Mock {
  static var staticMock: Mockingbird.StaticMock { fatalError("See 'Thunk Pruning' in the README") }
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.16.0", "module_name": "Backbone"])
  public var sourceLocation: Mockingbird.SourceLocation? { get { fatalError("See 'Thunk Pruning' in the README") } set { fatalError("See 'Thunk Pruning' in the README") } }

  fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
    Mockingbird.checkVersion(for: self)
    self.sourceLocation = sourceLocation
  }

  // MARK: Mocked `encode64`(_ `value`: Int64...)

  public func `encode64`(_ `value`: Int64...) -> String? { fatalError("See 'Thunk Pruning' in the README") }

  public func `encode64`(_ `value`: @escaping @autoclosure () -> [Int64]) -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, ([Int64]) -> String?, String?> { fatalError("See 'Thunk Pruning' in the README") }

  public func `encode64`(_ `value`: Int64...) -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, ([Int64]) -> String?, String?> { fatalError("See 'Thunk Pruning' in the README") }

  // MARK: Mocked `encode64`(_ `values`: [Int64])

  public func `encode64`(_ `values`: [Int64]) -> String? { fatalError("See 'Thunk Pruning' in the README") }

  public func `encode64`(_ `values`: @escaping @autoclosure () -> [Int64]) -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, ([Int64]) -> String?, String?> { fatalError("See 'Thunk Pruning' in the README") }
}
  1. The expected mocking code that should be generated (or a description)
    Without any of the redundant redeclarations

Environment

  • Mockingbird CLI version (mockingbird version): 0.16.0
  • Xcode and macOS version (are you running a beta?): XCode 12, Mac Catalina
  • Swift version (swift --version): Apple Swift version 5.3 (swiftlang-1200.0.29.2 clang-1200.0.30.1)
  • Installation method (CocoaPods, Carthage, from source, etc)
  • Unit testing framework (XCTest, Quick + Nimble, etc): XCTest
  • Does your project use .mockingbird-ignore? No
  • Are you using supporting source files? To my knowledge, yes.

Generated mock for generic with two type parameters has them reversed

Description

I have a generic type with two types. The generated mock for it seems to have reversed those types in some cases.

Class

class SectionViewModel<Row, Context> {
    
    // MARK: - state
    
    var title: String = ""
    var rows = [Row]()
    var context: Context?
    
    // MARK: - ctors
    
    init(title: String = "", rows: [Row] = [], context: Context? = nil) {
        self.title = title
        self.rows.append(contentsOf: rows)
        self.context = context
    }
    
    // MARK: - interface
    
    func add(row: Row) {
        self.rows.append(row)
    }
}

Generated Mock

// MARK: - Mocked SectionViewModel

public final class SectionViewModelMock<Context, Row>: TableSide.SectionViewModel<Context, Row>, Mockingbird.Mock {
  static var staticMock: Mockingbird.StaticMock {
    let runtimeGenericTypeNames = ["\(Context.self)", "\(Row.self)"].joined(separator: ",")
    let staticMockIdentifier = "SectionViewModelMock<Context, Row>," + runtimeGenericTypeNames
    if let staticMock = genericTypesStaticMocks.value[staticMockIdentifier] { return staticMock }
    let staticMock = Mockingbird.StaticMock()
    genericTypesStaticMocks.update { $0[staticMockIdentifier] = staticMock }
    return staticMock
  }
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.7.0", "module_name": "TableSide"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      SectionViewModelMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  public enum InitializerProxy {
    public static func initialize(title: String, rows: [Row], context: Context?, __file: StaticString = #file, __line: UInt = #line) -> SectionViewModelMock<Context, Row> {
      let mock: SectionViewModelMock<Context, Row> = SectionViewModelMock<Context, Row>(title: `title`, rows: `rows`, context: `context`)
      mock.sourceLocation = SourceLocation(__file, __line)
      return mock
    }
  }

  // MARK: Mocked context

  override public var `context`: Context? {
    get {
      let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "context.get", arguments: [])
      mockingContext.didInvoke(invocation)
      return (stubbingContext.implementation(for: invocation) as! () -> Context?)()
    }
    set {
      let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "context.set", arguments: [ArgumentMatcher(newValue)])
      mockingContext.didInvoke(invocation)
      let implementation = stubbingContext.implementation(for: invocation, optional: true)
      if let concreteImplementation = implementation as? (Context?) -> Void {
        concreteImplementation(newValue)
      } else {
        (implementation as? () -> Void)?()
      }
    }
  }

  public func getContext() -> Mockingbird.Mockable<Mockingbird.VariableDeclaration, () -> Context?, Context?> {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "context.get", arguments: [])
    return Mockingbird.Mockable<Mockingbird.VariableDeclaration, () -> Context?, Context?>(mock: self, invocation: invocation)
  }

  public func setContext(_ newValue: @escaping @autoclosure () -> Context?) -> Mockingbird.Mockable<Mockingbird.VariableDeclaration, (Context?) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(newValue)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "context.set", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.VariableDeclaration, (Context?) -> Void, Void>(mock: self, invocation: invocation)
  }

  // MARK: Mocked title

  override public var `title`: String {
    get {
      let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "title.get", arguments: [])
      mockingContext.didInvoke(invocation)
      return (stubbingContext.implementation(for: invocation) as! () -> String)()
    }
    set {
      let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "title.set", arguments: [ArgumentMatcher(newValue)])
      mockingContext.didInvoke(invocation)
      let implementation = stubbingContext.implementation(for: invocation, optional: true)
      if let concreteImplementation = implementation as? (String) -> Void {
        concreteImplementation(newValue)
      } else {
        (implementation as? () -> Void)?()
      }
    }
  }

  public func getTitle() -> Mockingbird.Mockable<Mockingbird.VariableDeclaration, () -> String, String> {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "title.get", arguments: [])
    return Mockingbird.Mockable<Mockingbird.VariableDeclaration, () -> String, String>(mock: self, invocation: invocation)
  }

  public func setTitle(_ newValue: @escaping @autoclosure () -> String) -> Mockingbird.Mockable<Mockingbird.VariableDeclaration, (String) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(newValue)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "title.set", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.VariableDeclaration, (String) -> Void, Void>(mock: self, invocation: invocation)
  }

  // MARK: Mocked `add`(row: Row)

  public override func `add`(row: Row) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`add`(row: Row) -> Void", arguments: [Mockingbird.ArgumentMatcher(`row`)])
    mockingContext.didInvoke(invocation)
    let implementation = stubbingContext.implementation(for: invocation, optional: true)
    if let concreteImplementation = implementation as? (Row) -> Void {
      concreteImplementation(`row`)
    } else {
      (implementation as? () -> Void)?()
    }
  }

  public func `add`(row: @escaping @autoclosure () -> Row) -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, (Row) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`row`)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`add`(row: Row) -> Void", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.MethodDeclaration, (Row) -> Void, Void>(mock: self, invocation: invocation)
  }

  // MARK: Mocked init(title: String, rows: [Row], context: Context?)

  public required override init(title: String, rows: [Row], context: Context?) {
    super.init(title: `title`, rows: `rows`, context: `context`)
    Mockingbird.checkVersion(for: self)
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "init(title: String, rows: [Row], context: Context?) ", arguments: [Mockingbird.ArgumentMatcher(`title`), Mockingbird.ArgumentMatcher(`rows`), Mockingbird.ArgumentMatcher(`context`)])
    mockingContext.didInvoke(invocation)
  }
}

/// Create a source-attributed `TableSide.SectionViewModel<Context, Row><Context, Row>` class mock metatype.
public func mock<Context, Row>(file: StaticString = #file, line: UInt = #line, _ type: SectionViewModelMock<Context, Row>.Type) -> SectionViewModelMock<Context, Row>.InitializerProxy.Type {
  return SectionViewModelMock<Context, Row>.InitializerProxy.self
}

Environment

  • Mockingbird CLI version - CLI reports 0.7.0, but I believe I updated to 0.7.2
  • Xcode and macOS version - Xcode 11.1, macOS Catalina Public Beta 10.15 - 19A582a
  • Swift version - 5.1
  • Installation method - SPM
  • Unit testing framework - XCTest
  • Does your project use .mockingbird-ignore? No.

MyTypeMock does not conform to protocol NSObjectProtocol

Hi,

In my project, there are supporting source files related to NSObjectProtocol. but the error "MyTypeDelegateMock does not conform to protocol NSObjectProtocol" is not resolved.

protocol DTPhotoViewerControllerDelegate: NSObjectProtocol {
}
protocol MyTypeDelegate: DTPhotoViewerControllerDelegate {
}

In MyProjectMocks.generated.swift file, i have this error:

// MARK: - Mocked MyTypeDelegate

public final class MyTypeDelegateMock: MyProject.MyTypeDelegate, Mockingbird.Mock {
}

CLI upgrading tips

New Issue Checklist

Description

First of all, thank you very much for an amazing mocking framework. It saved so much time for us already 🚀

I'm seeking suggestions on how to upgrade CLI with updates to the Mockingbird dependency. Everything works fine on CI since the CI environment is clean on every build. However, when upgrading lib locally there's a mismatch between CLI and XCode version. I was able to solve it by deleting the existing binary with something like this: rm -rf /usr/local/bin/mockingbird. But I'm wondering if there's a suggested way to do this and maybe a way to automate this.

Currently, we have something like this in our build phase:

which mockingbird 2>&1 >/dev/null
if [ $? -ne 0 ]; then
  DERIVED_DATA=$(dirname $(dirname $BUILD_DIR))
  (cd "${DERIVED_DATA}/SourcePackages/checkouts/mockingbird" && make install-prebuilt)
fi

I'm thinking to add a version check here. However, this is getting too complicated and something tells me that there's a better way 🙂

Environment

  • Installation method (CocoaPods, Carthage, from source, etc) - SPM
  • Unit testing framework (XCTest, Quick + Nimble, etc) - Quick + Nimble
  • Does your project use .mockingbird-ignore? - No
  • Are you using supporting source files? - No

Mockingbird CI-safe won't find dylib #3 when run from a symlink for the first time

New Issue Checklist

  • [✅] I updated my Mockingbird framework and CLI to the latest version
  • [✅] I searched for existing GitHub issues

Description

mockingbird generate doesn't work when it is run for the first time via a symlink. The lib_InternalSwiftSyntaxParser.dylib file gets created in the same file location as the symlink, and Mockingbird complains that it can't find it.

Running the Mockingbird binary directly creates the lib_InternalSwiftSyntaxParser.dylib in the same location as the real binary and works correctly. Once the .dylib is in the right place, running Mockingbird via a symlink works correctly too.

Generator Bugs

# The symlink setup in project root directory
?130 MockingbirdTestProject % ls -l Mockingbird-cisafe                                 
total 0
drwxr-xr-x  4 shocking  staff  128 28 Jan 15:37 0.16.0
lrwxr-xr-x  1 shocking  staff   94 28 Jan 15:37 mockingbird -> /Users/shocking/checkouts/sandbox/MockingbirdTestProject/Mockingbird-cisafe/0.16.0/mockingbird

# Running Mockingbird symlink from command line
√ MockingbirdTestProject % ./Mockingbird-cisafe/mockingbird generate --targets 'MockingbirdTestProject' --outputs "./MockingbirdMocks/MockingbirdTestProjectMocks.generated.swift" --support "./MockingbirdSupport" --disable-cache --verbose
Parse Arguments - Took 0.48 ms
Using inferred Xcode project at /Users/shocking/Documents/checkouts/sandbox/MockingbirdTestProject/MockingbirdTestProject.xcodeproj
Parse Xcode Project - Took 6.96 ms
Resolved product module name 'MockingbirdTestProject' for target 'MockingbirdTestProject'
Resolved product module name 'MockingbirdTestProject' for target 'MockingbirdTestProject'
Extract Sources - Took 3.31 ms
Found 3 source files and 14 dependency source files for target 'MockingbirdTestProject'
dyld: lazy symbol binding failed: can't resolve symbol _swiftparse_syntax_structure_versioning_identifier in /Users/shocking/Documents/checkouts/sandbox/MockingbirdTestProject/Mockingbird-cisafe/mockingbird because dependent dylib #3 could not be loaded
dyld: can't resolve symbol _swiftparse_syntax_structure_versioning_identifier in /Users/shocking/Documents/checkouts/sandbox/MockingbirdTestProject/Mockingbird-cisafe/mockingbird because dependent dylib #3 could not be loaded

# dylib created in symlink location
?6 MockingbirdTestProject % ls -l Mockingbird-cisafe
total 14616
drwxr-xr-x  4 shocking  staff      128 28 Jan 15:37 0.16.0
-rw-r--r--  1 shocking  staff  7481136 28 Jan 15:39 lib_InternalSwiftSyntaxParser.dylib
lrwxr-xr-x  1 shocking  staff       94 28 Jan 15:37 mockingbird -> /Users/shocking/checkouts/sandbox/MockingbirdTestProject/Mockingbird-cisafe/0.16.0/mockingbird

# Nothing in the binary's location
√ MockingbirdTestProject % ls -l Mockingbird-cisafe/0.16.0 
total 90176
-rw-r--r--  1 shocking  staff  13282884 28 Jan 15:37 Mockingbird-cisafe.zip
-rwxr-xr-x  1 shocking  staff  32520768  8 Oct 15:38 mockingbird

# Running Mockingbird binary directly
?130 MockingbirdTestProject % ./Mockingbird-cisafe/0.16.0/mockingbird generate --targets 'MockingbirdTestProject' --outputs "./MockingbirdMocks/MockingbirdTestProjectMocks.generated.swift" --support "./MockingbirdSupport" --disable-cache --verbose
Using inferred Xcode project at /Users/shocking/Documents/checkouts/sandbox/MockingbirdTestProject/MockingbirdTestProject.xcodeproj
Parse Xcode Project - Took 7.08 ms
Resolved product module name 'MockingbirdTestProject' for target 'MockingbirdTestProject'
Resolved product module name 'MockingbirdTestProject' for target 'MockingbirdTestProject'
Extract Sources - Took 3.22 ms
Found 3 source files and 14 dependency source files for target 'MockingbirdTestProject'
Parsed 3 import declarations and 0 compiler directives in source file at /Users/shocking/Documents/checkouts/sandbox/MockingbirdTestProject/MockingbirdSupport/UIKit/UIViewController.swift
Parsed dependency source structure for module 'UIKit' at /Users/shocking/Documents/checkouts/sandbox/MockingbirdTestProject/MockingbirdSupport/UIKit/UIViewController.swift
Parsed 1 import declaration and 0 compiler directives in source file at /Users/shocking/Documents/checkouts/sandbox/MockingbirdTestProject/MockingbirdSupport/Swift/Misc.swift
# etc... works correctly!

Environment

  • Mockingbird CLI version (mockingbird version) - 0.16.0
  • Xcode and macOS version (are you running a beta?) - Xcode 12.4 (12D4e), macOS 10.15.7
  • Swift version (swift --version) - Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28), Target: x86_64-apple-darwin19.6.0
  • Installation method (CocoaPods, Carthage, from source, etc) - downloading CI-safe binary manually
  • Unit testing framework (XCTest, Quick + Nimble, etc) - N/A
  • Does your project use .mockingbird-ignore? - no
  • Are you using supporting source files? - yes

Some way to generate the mocks in the structure base of a private pod.

New Issue Checklist

Description

I would like some way to set the framework to generate the mocks. In the Cocoapod example project, the pod is installed as a framework so I was not able to generate the mocks using this amazing library.

Example

I can add the MyPod-Example target to generate the mocks. But I want to generate the mocks for MyPod.

If you create a template with pod lib create MyPod it is easy to have the environment of my case.

Thank you much!!! 😍

Ignore extension methods

New Issue Checklist

Description

Generator mocks extension methods, which it shouldn't.

Generator Bugs

$ mockingbird generate \
  --only-protocols \
  --targets 'Sample' \
  --outputs 'Sample/MockingbirdMocks/SampleMocks.generated.swift'
  1. A minimal example of the original source
protocol Abc {
}

extension Abc {
    func foo() {
    }
}
  1. The actual mocking code generated
@testable import Mockingbird
@testable import Sample
import Foundation
import Swift
import SwiftUI
import UIKit

private var genericTypesStaticMocks = Mockingbird.Synchronized<[String: Mockingbird.StaticMock]>([:])

// MARK: - Mocked Abc

public final class AbcMock: Sample.Abc, Mockingbird.Mock {
  static let staticMock = Mockingbird.StaticMock()
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.9.0", "module_name": "Sample"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      AbcMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
    Mockingbird.checkVersion(for: self)
    self.sourceLocation = sourceLocation
  }

  // MARK: Mocked `foo`()

  public func `foo`() -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`() -> Void", arguments: [])
    mockingContext.didInvoke(invocation)
    let implementation = stubbingContext.implementation(for: invocation, optional: true)
    if let concreteImplementation = implementation as? () -> Void {
      concreteImplementation()
    } else {
      (implementation as? () -> Void)?()
    }
  }

  public func `foo`() -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, () -> Void, Void> {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`() -> Void", arguments: [])
    return Mockingbird.Mockable<Mockingbird.MethodDeclaration, () -> Void, Void>(mock: self, invocation: invocation)
  }
}

/// Create a source-attributed `Sample.Abc` concrete protocol mock instance.
public func mock(file: StaticString = #file, line: UInt = #line, _ type: Sample.Abc.Protocol) -> AbcMock {
  return AbcMock(sourceLocation: SourceLocation(file, line))
}

Environment

  • Mockingbird CLI version 0.9.0
  • Xcode 11.3 and macOS 10.15.2
  • Swift version Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
  • Installation method CocoaPods

An expected generic type in Mock class from generic class

New Issue Checklist

Description

The generator produces a wrong Mock class with the case below

class Animal<T> {
    func eat(food: T) {
        
    }
}
class AnyFoodAnimal: Animal<Any> {}

Expected:

public final class AnyFoodAnimalMock: Pulse.AnyFoodAnimal, Mockingbird.Mock
...

Output:

public final class AnyFoodAnimalMock<T>: Pulse.AnyFoodAnimal<T>, Mockingbird.Mock
...

Generator Bugs

@testable import Mockingbird
@testable import Pulse
import Foundation
import Swift
import UIKit

private var genericTypesStaticMocks = Mockingbird.Synchronized<[String: Mockingbird.StaticMock]>([:])

// MARK: - Mocked Animal

public final class AnimalMock<T>: Pulse.Animal<T>, Mockingbird.Mock {
  static var staticMock: Mockingbird.StaticMock {
    let runtimeGenericTypeNames = ["\(T.self)"].joined(separator: ",")
    let staticMockIdentifier = "AnimalMock<T>," + runtimeGenericTypeNames
    if let staticMock = genericTypesStaticMocks.value[staticMockIdentifier] { return staticMock }
    let staticMock = Mockingbird.StaticMock()
    genericTypesStaticMocks.update { $0[staticMockIdentifier] = staticMock }
    return staticMock
  }
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.10.0", "module_name": "Pulse"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      AnimalMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
    super.init()
    Mockingbird.checkVersion(for: self)
    self.sourceLocation = sourceLocation
  }

  // MARK: Mocked `eat`(`food`: T)

  public override func `eat`(`food`: T) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`eat`(`food`: T) -> Void", arguments: [Mockingbird.ArgumentMatcher(`food`)])
    mockingContext.didInvoke(invocation)
    let implementation = stubbingContext.implementation(for: invocation, optional: true)
    if let concreteImplementation = implementation as? (T) -> Void {
      concreteImplementation(`food`)
    } else {
      (implementation as? () -> Void)?()
    }
  }

  public func `eat`(`food`: @escaping @autoclosure () -> T) -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, (T) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`food`)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`eat`(`food`: T) -> Void", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.MethodDeclaration, (T) -> Void, Void>(mock: self, invocation: invocation)
  }
}

/// Create a source-attributed `Pulse.Animal<T><T>` concrete class mock instance.
public func mock<T>(file: StaticString = #file, line: UInt = #line, _ type: AnimalMock<T>.Type) -> AnimalMock<T> {
  return AnimalMock<T>(sourceLocation: SourceLocation(file, line))
}

// MARK: - Mocked AnyFoodAnimal

public final class AnyFoodAnimalMock<T>: Pulse.AnyFoodAnimal<T>, Mockingbird.Mock {
  static var staticMock: Mockingbird.StaticMock {
    let runtimeGenericTypeNames = ["\(T.self)"].joined(separator: ",")
    let staticMockIdentifier = "AnyFoodAnimalMock<T>," + runtimeGenericTypeNames
    if let staticMock = genericTypesStaticMocks.value[staticMockIdentifier] { return staticMock }
    let staticMock = Mockingbird.StaticMock()
    genericTypesStaticMocks.update { $0[staticMockIdentifier] = staticMock }
    return staticMock
  }
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.10.0", "module_name": "Pulse"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      AnyFoodAnimalMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
    super.init()
    Mockingbird.checkVersion(for: self)
    self.sourceLocation = sourceLocation
  }

  // MARK: Mocked `eat`(`food`: T)

  public override func `eat`(`food`: T) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`eat`(`food`: T) -> Void", arguments: [Mockingbird.ArgumentMatcher(`food`)])
    mockingContext.didInvoke(invocation)
    let implementation = stubbingContext.implementation(for: invocation, optional: true)
    if let concreteImplementation = implementation as? (T) -> Void {
      concreteImplementation(`food`)
    } else {
      (implementation as? () -> Void)?()
    }
  }

  public func `eat`(`food`: @escaping @autoclosure () -> T) -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, (T) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`food`)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`eat`(`food`: T) -> Void", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.MethodDeclaration, (T) -> Void, Void>(mock: self, invocation: invocation)
  }
}

/// Create a source-attributed `Pulse.AnyFoodAnimal<T><T>` concrete class mock instance.
public func mock<T>(file: StaticString = #file, line: UInt = #line, _ type: AnyFoodAnimalMock<T>.Type) -> AnyFoodAnimalMock<T> {
  return AnyFoodAnimalMock<T>(sourceLocation: SourceLocation(file, line))
}
$ mockingbird generate

If the generator produces code that is malformed or does not compile, please provide:

  1. A minimal example of the original source
  2. The actual mocking code generated
  3. The expected mocking code that should be generated (or a description)

Framework Bugs

Please provide a minimal example of your unit testing code, including any errors.

Environment

  • Mockingbird CLI version (mockingbird version)
  • Xcode and macOS version (are you running a beta?)
  • Swift version (swift --version)
  • Installation method (CocoaPods, Carthage, from source, etc)
  • Unit testing framework (XCTest, Quick + Nimble, etc)
  • Does your project use .mockingbird-ignore?

Making the lib work on a CI without embedding a cisafe bin

I've been testing MockingBird to migrate from Cuckoo. Although the lib is working great and I really like the API the fact that you need to version a 35mb binary to your git (for your CI to run) is a real dealbreaker for me. I was wondering if it was something that could be changed in order not to have a cisafe bin or if it was a technical constraint that could not be solved ?

Great lib anyway huge thanks for the great work 👍

Use PRODUCT_NAME not productName

New Issue Checklist

Description

When PRODUCT_MODULE_NAME not specified, use PRODUCT_NAME from build settings to infer module name.
Target's productName is a different thing, and should not be used.

https://github.com/birdrides/mockingbird/blob/c80b79fee8612814b6d3b399d7fac3be5dc6f926/MockingbirdGenerator/Parser/Cache/CodableTarget.swift#L136

For example:

  • create new project in Xcode
  • pick and rename a target
  • target's productName stays unchanged

project.zip

Environment

  • Mockingbird CLI version 0.9.0
  • Xcode 11.3 and macOS 10.15.2
  • Swift version Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)

Add "throws" to sequence of values closure

Would it be possible to have the closure () -> ReturnType include throwing functions? So like the first time you call a method, it returns something but the second time it throws an error, or vice versa

Reference: https://github.com/birdrides/mockingbird#sequence-of-values-0120

public func sequence<FunctionType, ReturnType>(of lazyValues: (() -> ReturnType)...)
  -> StubImplementation<FunctionType, ReturnType> {
    var index = 0
    let implementation: () -> ReturnType = {
      let value = lazyValues[index]()
      if index+1 < lazyValues.count { index += 1 }
      return value
    }
    return StubImplementation<FunctionType, ReturnType>(handler: implementation, callback: nil)
}```

Ambiguous methods generated

New Issue Checklist

Description

Generator outputs duplicate symbols for a method:

  public func `foo`() -> Void
  public func `foo`() -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, () -> Void, Void>

I have no idea what is supposed to be generated, since I'm trying this framework for the first time.

Generator Bugs

$ mockingbird generate \
  --only-protocols \
  --targets 'Sample' \
  --outputs 'Sample/MockingbirdMocks/SampleMocks.generated.swift'
  1. A minimal example of the original source
protocol Abc {
    func foo()
}
  1. The actual mocking code generated
@testable import Mockingbird
@testable import Sample
import Foundation
import Swift
import SwiftUI
import UIKit

private var genericTypesStaticMocks = Mockingbird.Synchronized<[String: Mockingbird.StaticMock]>([:])

// MARK: - Mocked Abc

public final class AbcMock: Sample.Abc, Mockingbird.Mock {
  static let staticMock = Mockingbird.StaticMock()
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.9.0", "module_name": "Sample"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      AbcMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
    Mockingbird.checkVersion(for: self)
    self.sourceLocation = sourceLocation
  }

  // MARK: Mocked `foo`()

  public func `foo`() -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`() -> Void", arguments: [])
    mockingContext.didInvoke(invocation)
    let implementation = stubbingContext.implementation(for: invocation, optional: true)
    if let concreteImplementation = implementation as? () -> Void {
      concreteImplementation()
    } else {
      (implementation as? () -> Void)?()
    }
  }

  public func `foo`() -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, () -> Void, Void> {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`() -> Void", arguments: [])
    return Mockingbird.Mockable<Mockingbird.MethodDeclaration, () -> Void, Void>(mock: self, invocation: invocation)
  }
}

/// Create a source-attributed `Sample.Abc` concrete protocol mock instance.
public func mock(file: StaticString = #file, line: UInt = #line, _ type: Sample.Abc.Protocol) -> AbcMock {
  return AbcMock(sourceLocation: SourceLocation(file, line))
}
  1. The expected mocking code that should be generated (or a description)

TBD

Environment

  • Mockingbird CLI version 0.9.0
  • Xcode 11.3 and macOS 10.15.2
  • Swift version Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
  • Installation method CocoaPods

Unescaped reserved keyword in argument

New Issue Checklist

Description

Escaped reserved keywords in source code become unescaped in generated mocks.

Generator Bugs

$ mockingbird generate \
  --only-protocols \
  --targets 'Sample' \
  --outputs 'Sample/MockingbirdMocks/SampleMocks.generated.swift'
  1. A minimal example of the original source
protocol One {
    func foo(_ `inout`: Int)
    func bar(`inout` x: Int)
}
  1. The actual mocking code generated
//
//  SampleMocks.generated.swift
//  Sample
//
//  Generated by Mockingbird v0.9.0.
//  DO NOT EDIT
//

@testable import Mockingbird
@testable import Sample
import Foundation
import Swift
import UIKit

private var genericTypesStaticMocks = Mockingbird.Synchronized<[String: Mockingbird.StaticMock]>([:])

// MARK: - Mocked One

public final class OneMock: Sample.One, Mockingbird.Mock {
  static let staticMock = Mockingbird.StaticMock()
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.9.0", "module_name": "Sample"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      OneMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
    Mockingbird.checkVersion(for: self)
    self.sourceLocation = sourceLocation
  }

  // MARK: Mocked `bar`(inout x: Int)

  public func `bar`(inout x: Int) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`bar`(inout x: Int) -> Void", arguments: [Mockingbird.ArgumentMatcher(`x`)])
    mockingContext.didInvoke(invocation)
    let implementation = stubbingContext.implementation(for: invocation, optional: true)
    if let concreteImplementation = implementation as? (Int) -> Void {
      concreteImplementation(`x`)
    } else {
      (implementation as? () -> Void)?()
    }
  }

  public func `bar`(inout x: @escaping @autoclosure () -> Int) -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, (Int) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`x`)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`bar`(inout x: Int) -> Void", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.MethodDeclaration, (Int) -> Void, Void>(mock: self, invocation: invocation)
  }

  // MARK: Mocked `foo`(_ inout: Int)

  public func `foo`(_ inout: Int) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ inout: Int) -> Void", arguments: [Mockingbird.ArgumentMatcher(`inout`)])
    mockingContext.didInvoke(invocation)
    let implementation = stubbingContext.implementation(for: invocation, optional: true)
    if let concreteImplementation = implementation as? (Int) -> Void {
      concreteImplementation(`inout`)
    } else {
      (implementation as? () -> Void)?()
    }
  }

  public func `foo`(_ inout: @escaping @autoclosure () -> Int) -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, (Int) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`inout`)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ inout: Int) -> Void", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.MethodDeclaration, (Int) -> Void, Void>(mock: self, invocation: invocation)
  }
}

/// Create a source-attributed `Sample.One` concrete protocol mock instance.
public func mock(file: StaticString = #file, line: UInt = #line, _ type: Sample.One.Protocol) -> OneMock {
  return OneMock(sourceLocation: SourceLocation(file, line))
}
  1. The expected mocking code that should be generated (or a description)
public func `bar`(`inout` x: Int) -> Void {

public func `bar`(`inout` x: @escaping @autoclosure () -> Int) -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, (Int) -> Void, Void> {

public func `foo`(_ `inout`: Int) -> Void {

public func `foo`(_ `inout`: @escaping @autoclosure () -> Int) -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, (Int) -> Void, Void> {

Environment

  • Mockingbird CLI version 0.9.0
  • Xcode 11.3.1 and macOS version 10.15.3
  • Swift version Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
  • Installation method CocoaPods

Feature-Request: Enable calling original implementation if no stub is provided.

Sometimes, I might just want to create a version of my concrete type that is the real object, except that the invocations of functions and the get/set of properties can be verified.

From a quick overview of the architecture, this seems totally feasible. This is because mocks of concrete types are created by Mockingbird via subclassing that concrete type.

Currently, whenever there is no stub of the desired/function/property provided for the mock class, fatalError(self.stubbingContext.failTest(for: invocation)) is called.

But we could also just use the actual implementation with just super call.

Ignoring any files produces an empty generated file

Description

If I put even a single file in my .mockingbird-ignore, the generator will generate no mocks.

Example

My .mockingbird-ignore looks like this:

Locator.swift
SectionViewModel.swift

Resulting complete mocks file:

//
//  TableSideMocks.generated.swift
//  TableSide
//
//  Generated by Mockingbird v0.7.0.
//  DO NOT EDIT
//

@testable import Mockingbird
@testable import TableSide
import Foundation

If I remove the text from the ignore file, the mocks generate fine, although the ones in question don't compile.

Environment

  • Mockingbird CLI version - 0.7.0
  • Xcode and macOS version - Xcode 11.1, macOS Catalina Beta
  • Swift version - 5.1
  • Installation method - SPM
  • Unit testing framework - XCTest
  • Does your project use .mockingbird-ignore? Yup. :D

Screen Shot 2019-10-28 at 5 25 50 PM

Module 'Mockingbird' was not compiled for testing

New Issue Checklist

Description

Framework Bug

Module 'Mockingbird' was not compiled for testing

Installation method -> Swift Package Manager
Xcode version -> 12.4
macOS version -> 10.15.7
mockingbird version -> 16.0
swift --version -> Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28)
Test Suite -> XCTest

Issue

After following installation instructions and compiling our project everything generates and builds, but when attempting to run the test suite it fails to compile with error Module 'Mockingbird' was not compiled for testing in the *.generated.swift file.
Framework was added under our 'Tests' target

Screenshot 2021-01-11 at 11 07 18

Compile error with Objective-C annotations

New Issue Checklist

Description

The .generated.swift includes @objc annotation and the file doesn't compile.

Generator Bugs

$ mockingbird generate
  1. A minimal example of the original source
    Given a class:
@objc(EBMPerson)
class Person: NSObject {
    @objc(ebm_speak)
    func speak() {}
}
  1. The actual mocking code generated
  @objc(ebm_speak)
  public override func `speak`() -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`speak`() -> Void", arguments: [])
    mockingContext.didInvoke(invocation)
    let implementation = stubbingContext.implementation(for: invocation, optional: true)
    if let concreteImplementation = implementation as? () -> Void {
      concreteImplementation()
    } else {
      (implementation as? () -> Void)?()
    }
  }

  @objc(ebm_speak)
  public func `speak`() -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, () -> Void, Void> {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`speak`() -> Void", arguments: [])
    return Mockingbird.Mockable<Mockingbird.MethodDeclaration, () -> Void, Void>(mock: self, invocation: invocation)
  }
  1. The expected mocking code that should be generated (or a description)
    The expected mocking code should not include the @objc annotations as it is not supported.

Framework Bugs

N/A

Environment

  • Mockingbird CLI version (mockingbird version) 0.9.0
  • Xcode and macOS version (are you running a beta?) Version 11.3.1 (11C504), Mojave Version 10.14.6
  • Swift version (swift --version) Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
  • Installation method (CocoaPods, Carthage, from source, etc) Carthage
  • Unit testing framework (XCTest, Quick + Nimble, etc) Quick + Nimble
  • Does your project use .mockingbird-ignore? Yes

Invalid redeclaration of method conforming to several inherited protocols

New Issue Checklist

Description

Generator fails to merge conforming inheritance.

Generator Bugs

  1. A minimal example of the original source
protocol One {
    func foo(_ x: Int)
}

protocol Two {
    func foo(_ x: Int)
}

protocol Three : One, Two {}
  1. The actual mocking code generated
//
//  SampleMocks.generated.swift
//  Sample
//
//  Generated by Mockingbird v0.12.0.
//  DO NOT EDIT
//

@testable import Mockingbird
@testable import Sample
import Foundation
import Swift

private var genericTypesStaticMocks = Mockingbird.Synchronized<[String: Mockingbird.StaticMock]>([:])

// MARK: - Mocked One

public final class OneMock: Sample.One, Mockingbird.Mock {
  static let staticMock = Mockingbird.StaticMock()
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.12.0", "module_name": "Sample"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      OneMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
    Mockingbird.checkVersion(for: self)
    self.sourceLocation = sourceLocation
  }

  // MARK: Mocked `foo`(_ `x`: Int)

  public func `foo`(_ `x`: Int) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ `x`: Int) -> Void", arguments: [Mockingbird.ArgumentMatcher(`x`)])
    mockingContext.didInvoke(invocation) { () -> Void in
      let implementation = stubbingContext.implementation(for: invocation)
      if let concreteImplementation = implementation as? (Int) -> Void {
        concreteImplementation(`x`)
      } else if let concreteImplementation = implementation as? () -> Void {
        concreteImplementation()
      }
    }
  }

  public func `foo`(_ `x`: @escaping @autoclosure () -> Int) -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Int) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`x`)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ `x`: Int) -> Void", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Int) -> Void, Void>(mock: self, invocation: invocation)
  }
}

/// Initialize a protocol mock of `Sample.One`.
public func mock(_ type: Sample.One.Protocol, file: StaticString = #file, line: UInt = #line) -> OneMock {
  return OneMock(sourceLocation: SourceLocation(file, line))
}

// MARK: - Mocked Three

public final class ThreeMock: Sample.Three, Mockingbird.Mock {
  static let staticMock = Mockingbird.StaticMock()
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.12.0", "module_name": "Sample"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      ThreeMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
    Mockingbird.checkVersion(for: self)
    self.sourceLocation = sourceLocation
  }

  // MARK: Mocked `foo`(_ `x`: Int)

  public func `foo`(_ `x`: Int) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ `x`: Int) -> Void", arguments: [Mockingbird.ArgumentMatcher(`x`)])
    mockingContext.didInvoke(invocation) { () -> Void in
      let implementation = stubbingContext.implementation(for: invocation)
      if let concreteImplementation = implementation as? (Int) -> Void {
        concreteImplementation(`x`)
      } else if let concreteImplementation = implementation as? () -> Void {
        concreteImplementation()
      }
    }
  }

  public func `foo`(_ `x`: @escaping @autoclosure () -> Int) -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Int) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`x`)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ `x`: Int) -> Void", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Int) -> Void, Void>(mock: self, invocation: invocation)
  }

  // MARK: Mocked `foo`(_ `x`: Int)

  public func `foo`(_ `x`: Int) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ `x`: Int) -> Void", arguments: [Mockingbird.ArgumentMatcher(`x`)])
    mockingContext.didInvoke(invocation) { () -> Void in
      let implementation = stubbingContext.implementation(for: invocation)
      if let concreteImplementation = implementation as? (Int) -> Void {
        concreteImplementation(`x`)
      } else if let concreteImplementation = implementation as? () -> Void {
        concreteImplementation()
      }
    }
  }

  public func `foo`(_ `x`: @escaping @autoclosure () -> Int) -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Int) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`x`)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ `x`: Int) -> Void", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Int) -> Void, Void>(mock: self, invocation: invocation)
  }
}

/// Initialize a protocol mock of `Sample.Three`.
public func mock(_ type: Sample.Three.Protocol, file: StaticString = #file, line: UInt = #line) -> ThreeMock {
  return ThreeMock(sourceLocation: SourceLocation(file, line))
}

// MARK: - Mocked Two

public final class TwoMock: Sample.Two, Mockingbird.Mock {
  static let staticMock = Mockingbird.StaticMock()
  public let mockingContext = Mockingbird.MockingContext()
  public let stubbingContext = Mockingbird.StubbingContext()
  public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.12.0", "module_name": "Sample"])
  public var sourceLocation: Mockingbird.SourceLocation? {
    get { return stubbingContext.sourceLocation }
    set {
      stubbingContext.sourceLocation = newValue
      TwoMock.staticMock.stubbingContext.sourceLocation = newValue
    }
  }

  fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
    Mockingbird.checkVersion(for: self)
    self.sourceLocation = sourceLocation
  }

  // MARK: Mocked `foo`(_ `x`: Int)

  public func `foo`(_ `x`: Int) -> Void {
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ `x`: Int) -> Void", arguments: [Mockingbird.ArgumentMatcher(`x`)])
    mockingContext.didInvoke(invocation) { () -> Void in
      let implementation = stubbingContext.implementation(for: invocation)
      if let concreteImplementation = implementation as? (Int) -> Void {
        concreteImplementation(`x`)
      } else if let concreteImplementation = implementation as? () -> Void {
        concreteImplementation()
      }
    }
  }

  public func `foo`(_ `x`: @escaping @autoclosure () -> Int) -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Int) -> Void, Void> {
    let arguments: [Mockingbird.ArgumentMatcher] = [Mockingbird.resolve(`x`)]
    let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`foo`(_ `x`: Int) -> Void", arguments: arguments)
    return Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (Int) -> Void, Void>(mock: self, invocation: invocation)
  }
}

/// Initialize a protocol mock of `Sample.Two`.
public func mock(_ type: Sample.Two.Protocol, file: StaticString = #file, line: UInt = #line) -> TwoMock {
  return TwoMock(sourceLocation: SourceLocation(file, line))
}
  1. The expected mocking code that should be generated (or a description)

Removing duplicates should be enough to fix this.

Environment

  • Mockingbird CLI version 0.12.0
  • Xcode 11.4.1 and macOS 10.15.4
  • Swift version Apple Swift version 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51)
  • Installation method CocoaPods

Missing negating rules in .mockingbird-ignore

New Issue Checklist

Description

.mockingbird-ignore is not handling negated patterns (prefixed with !)

Mockingbird follows the same pattern format as .gitignore and scopes ignore files to their enclosing directory.

Generator Bugs

$ mockingbird generate \
  --only-protocols \
  --targets 'Sample' \
  --outputs 'MockingbirdMocks/SampleMocks.generated.swift'

Project tree

$ tree -a
.
├── MockingbirdMocks
│   └── SampleMocks.generated.swift
├── Sample
│   ├── .mockingbird-ignore
│   ├── AppDelegate.swift
│   ├── Assets.xcassets
│   │   ├── AppIcon.appiconset
│   │   │   └── Contents.json
│   │   └── Contents.json
│   ├── Base.lproj
│   │   ├── LaunchScreen.storyboard
│   │   └── Main.storyboard
│   ├── Info.plist
│   ├── One.swift
│   ├── SceneDelegate.swift
│   └── ViewController.swift
├── Sample.xcodeproj
│   ├── MockingbirdCache
│   │   └── Sample.lock
│   ├── project.pbxproj
│   ├── project.xcworkspace
│   │   ├── contents.xcworkspacedata
└── SampleTests
    ├── Info.plist
    └── SampleTests.swift

Contents of Sample/.mockingbird-ignore

*
!One.swift

The actual mocking code generated

//
//  SampleMocks.generated.swift
//  Sample
//
//  Generated by Mockingbird v0.9.0.
//  DO NOT EDIT
//

@testable import Mockingbird
@testable import Sample
import Foundation

Environment

  • Mockingbird CLI version 0.9.0
  • Xcode 11.3.1 macOS version 10.15.3
  • Swift version Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
  • Installation method CocoaPods

Mock generator should add compiler flags around OS-specific libraries (e.g. `AppKit` vs. `UIKit`)

New Issue Checklist

Description

The generator indiscriminately imports all packages and Apple Frameworks I use, without checking if they are OS-specific. This is a problem, as my tests will only ever have one.

The proposed solution is just to keep a list of any os-specific Apple Frameworks, and make sure the generator handles them correctly

Generator Bugs

If the generator produces code that is malformed or does not compile, please provide:

  1. A minimal example of the original source
#if os(OSX)
  import AppKit.NSImage
#elseif os(iOS) || os(tvOS) || os(watchOS)
  import UIKit.UIImage
#endif
  1. The actual mocking code generated
import AppKit.NSImage
import UIKit.UIImage
  1. The expected mocking code that should be generated (or a description)
#if os(OSX)
  import AppKit.NSImage
#elseif os(iOS) || os(tvOS) || os(watchOS)
  import UIKit.UIImage
#endif

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.