typealiased / mockingbird Goto Github PK
View Code? Open in Web Editor NEWA Swifty mocking framework for Swift and Objective-C.
Home Page: https://mockingbirdswift.com
License: MIT License
A Swifty mocking framework for Swift and Objective-C.
Home Page: https://mockingbirdswift.com
License: MIT License
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?
Generator incorrectly references generic type from inherited protocol.
protocol One {
typealias Arg<T> = T
func some<T>(_ x: Arg<T>)
}
class Two : One {
func some<T>(_ x: Arg<T>) {}
}
//
// 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))
}
// 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 {
0.12.0
11.4.1
and macOS 10.15.4
Apple Swift version 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51)
CocoaPods
Extra parens around closure parameter breaks mocked method.
$ mockingbird generate \
--only-protocols \
--targets 'Sample' \
--outputs 'Sample/MockingbirdMocks/SampleMocks.generated.swift'
protocol One : class {
func foo(_ x: ((Int) -> Void))
}
//
// 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`)])
// 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>())])
0.9.0
11.3.1
and macOS version 10.15.3
Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
CocoaPods
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.
import #target_name#
instead of import #project_name#
. This issue I was able to resolve by passing --disable-module-import
.public class SomeClass: TargetName.SomeClass, MockingBird.Mock
,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.
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.
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
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.
master
as of this issues creation date)11.4.1
Apple Swift version 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51)
)CocoaPods
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.
@testable import Mockingbird
in my AppMocks.generated.swift file.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.
swiftSyntaxParserDylib
variable in mainopen Package.swift
will make xcode resolve the dependencies. This works but then I cannot build because of my first bulletTo solve this I followed the following steps, unsuccessful so far
make setup-project
cd sources
to inspect the packageMockingbird
as a dependency to the commented out test targetswiftSyntaxParserDylib
manually aslet 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:
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?
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.
0.14.0
)5.2
)👋
Hello,
Could we get an updated binary that's built with Swift 5.3.1, please?
Thank you!
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.
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'
.mockingbird-ignore
? NoStubbing fails on metatype arguments –– matcher compares them by reference.
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).
0.9.0
11.3.1
and macOS version 10.15.3
Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
CocoaPods
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)
}
0.9.0
11.3.1
macOS version 10.15.3
Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
CocoaPods
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.
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())
}
}
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 #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
target 'mockingbird-bug-report' do
use_frameworks!
target 'mockingbird-bug-reportTests' do
inherit! :search_paths
pod "MockingbirdFramework"
end
end
mockingbird version
) 0.9.0swift --version
) Apple Swift version 5.1 (swiftlang-1100.0.270.13 clang-1100.0.33.7).mockingbird-ignore
? Nocan 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
mockingbird install
--project Login.xcodeproj
--target LoginExample
--destination LoginTests
Can you guide me how to generate LoginProtocol mocs .
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
mockingbird version
) 0.16.0
11.7
, 10.15.7
swift --version
) Apple Swift version 5.2.4 (swiftlang-1103.0.32.9 clang-1103.0.32.53)
CocoaPods
XCTest
.mockingbird-ignore
? No
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.)
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
Inferred return type of mock()
is not usable.
$ mockingbird generate \
--only-protocols \
--disable-cache \
--targets 'Sample' \
--outputs "${SRCROOT}/MockingbirdMocks/SampleMocks.generated.swift"
protocol Bird {
func fly()
}
//
// 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() }
Not sure yet.
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'
}
0.11.0
11.4
and macOS 10.15.4
Apple Swift version 5.2 (swiftlang-1103.0.32.1 clang-1103.0.32.29)
CocoaPods
Generator skips subscript
in a protocol.
$ mockingbird generate \
--only-protocols \
--targets 'Sample' \
--outputs 'Sample/MockingbirdMocks/SampleMocks.generated.swift'
protocol Third {
subscript(index: String) -> String? { get set }
}
// 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))
}
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)
}
0.9.0
11.3.1
macOS version 10.15.3
Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
CocoaPods
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
}
}
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:
public class Car: Codable {
private var brand: String
public init(brand: String) {
self.brand = brand
}
}
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)
}
}
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")
}
}
.mockingbird-ignore
? NoThe Ambiguous use of operator '~>'
error pops up while stubbing methods without parameter using a closure.
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)
}
0.11.0
11.4
and macOS version 10.15.4
Apple Swift version 5.2 (swiftlang-1103.0.32.1 clang-1103.0.32.29)
CocoaPods
XCTest
.mockingbird-ignore
? No
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.
#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)
}
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
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")
}
'
public class CodModel: Codable {
enum CodingKeys: String, CodingKey {
case name
}
public var name: String
public init(name: String) {
self.name = name
}
}
@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
}
mockingbird version
) 0.12.2swift --version
) 5.1.3.mockingbird-ignore
? NoWhen mocking non-generic types:
mock(SomeType.self)
When mocking generic types:
mock(SomeTypeMock<Int>.self)
And this difference seems undocumented.
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)
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
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
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.
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()
// ✅
mockingbird version
) => 0.6.1swift --version
) => 5.1.mockingbird-ignore
? => noIf 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
mockingbird version
)swift --version
).mockingbird-ignore
?Protocols with overloaded functions with a variadic signature and an input array signature leads to redeclarations in the generated code.
If the generator produces code that is malformed or does not compile, please provide:
public protocol HashidsGenerator {
associatedtype Char
func encode64(_ value: Int64...) -> String?
func encode64(_ values: [Int64]) -> String?
}
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") }
}
mockingbird version
): 0.16.0swift --version
): Apple Swift version 5.3 (swiftlang-1200.0.29.2 clang-1200.0.30.1).mockingbird-ignore
? NoI have a generic type with two types. The generated mock for it seems to have reversed those types in some cases.
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)
}
}
// 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
}
.mockingbird-ignore
? No.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 {
}
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 🙂
.mockingbird-ignore
? - Nomockingbird 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.
# 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!
mockingbird version
) - 0.16.0swift --version
) - Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28), Target: x86_64-apple-darwin19.6.0.mockingbird-ignore
? - noI 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.
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!!! 😍
Generator mocks extension methods, which it shouldn't.
$ mockingbird generate \
--only-protocols \
--targets 'Sample' \
--outputs 'Sample/MockingbirdMocks/SampleMocks.generated.swift'
protocol Abc {
}
extension Abc {
func foo() {
}
}
@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))
}
0.9.0
11.3
and macOS 10.15.2
Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
CocoaPods
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
...
@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:
Please provide a minimal example of your unit testing code, including any errors.
mockingbird version
)swift --version
).mockingbird-ignore
?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 👍
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.
For example:
productName
stays unchanged0.9.0
11.3
and macOS 10.15.2
Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
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)
}```
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.
$ mockingbird generate \
--only-protocols \
--targets 'Sample' \
--outputs 'Sample/MockingbirdMocks/SampleMocks.generated.swift'
protocol Abc {
func foo()
}
@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))
}
TBD
0.9.0
11.3
and macOS 10.15.2
Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
CocoaPods
Escaped reserved keywords in source code become unescaped in generated mocks.
$ mockingbird generate \
--only-protocols \
--targets 'Sample' \
--outputs 'Sample/MockingbirdMocks/SampleMocks.generated.swift'
protocol One {
func foo(_ `inout`: Int)
func bar(`inout` x: Int)
}
//
// 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))
}
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> {
0.9.0
11.3.1
and macOS version 10.15.3
Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
CocoaPods
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.
If I put even a single file in my .mockingbird-ignore, the generator will generate no mocks.
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.
.mockingbird-ignore
? Yup. :DModule '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
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
The .generated.swift
includes @objc annotation and the file doesn't compile.
$ mockingbird generate
@objc(EBMPerson)
class Person: NSObject {
@objc(ebm_speak)
func speak() {}
}
@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)
}
@objc
annotations as it is not supported.N/A
mockingbird version
) 0.9.0swift --version
) Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15).mockingbird-ignore
? YesGenerator fails to merge conforming inheritance.
protocol One {
func foo(_ x: Int)
}
protocol Two {
func foo(_ x: Int)
}
protocol Three : One, Two {}
//
// 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))
}
Removing duplicates should be enough to fix this.
0.12.0
11.4.1
and macOS 10.15.4
Apple Swift version 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51)
CocoaPods
.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.
$ 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
0.9.0
11.3.1
macOS version 10.15.3
Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
CocoaPods
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
If the generator produces code that is malformed or does not compile, please provide:
#if os(OSX)
import AppKit.NSImage
#elseif os(iOS) || os(tvOS) || os(watchOS)
import UIKit.UIImage
#endif
import AppKit.NSImage
import UIKit.UIImage
#if os(OSX)
import AppKit.NSImage
#elseif os(iOS) || os(tvOS) || os(watchOS)
import UIKit.UIImage
#endif
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.