mirror of
https://github.com/bitwarden/ios.git
synced 2025-12-11 04:34:55 -06:00
[PM-23496] Add Sourcery library to automatically generate mocks (#1724)
This commit is contained in:
parent
fe7b68fa1c
commit
bbb93bdef1
@ -122,6 +122,14 @@
|
||||
<key>Type</key>
|
||||
<string>PSChildPaneSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>File</key>
|
||||
<string>Acknowledgements/Sourcery</string>
|
||||
<key>Title</key>
|
||||
<string>Sourcery</string>
|
||||
<key>Type</key>
|
||||
<string>PSChildPaneSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>File</key>
|
||||
<string>Acknowledgements/swift-custom-dump</string>
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreferenceSpecifiers</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>MIT License
|
||||
|
||||
Copyright (c) 2016-2021 Krzysztof Zabłocki
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
</string>
|
||||
<key>License</key>
|
||||
<string>MIT</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
2
AuthenticatorShared/Sourcery/Generated/.gitignore
vendored
Normal file
2
AuthenticatorShared/Sourcery/Generated/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Ignore SwiftGen generated files
|
||||
*.swift
|
||||
18
AuthenticatorShared/Sourcery/sourcery.yml
Normal file
18
AuthenticatorShared/Sourcery/sourcery.yml
Normal file
@ -0,0 +1,18 @@
|
||||
sources:
|
||||
- ..
|
||||
|
||||
templates:
|
||||
- ../../Sourcery/Templates/AutoMockable.stencil
|
||||
|
||||
output:
|
||||
Generated
|
||||
|
||||
exclude:
|
||||
- Generated
|
||||
- Tests
|
||||
- TestHelpers
|
||||
- Fixtures
|
||||
|
||||
args:
|
||||
autoMockableImports: ["BitwardenKit", "BitwardenSdk", "Combine"]
|
||||
autoMockableTestableImports: ["AuthenticatorShared"]
|
||||
2
BitwardenShared/Sourcery/Generated/.gitignore
vendored
Normal file
2
BitwardenShared/Sourcery/Generated/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Ignore SwiftGen generated files
|
||||
*.swift
|
||||
18
BitwardenShared/Sourcery/sourcery.yml
Normal file
18
BitwardenShared/Sourcery/sourcery.yml
Normal file
@ -0,0 +1,18 @@
|
||||
sources:
|
||||
- ..
|
||||
|
||||
templates:
|
||||
- ../../Sourcery/Templates/AutoMockable.stencil
|
||||
|
||||
output:
|
||||
Generated
|
||||
|
||||
exclude:
|
||||
- Generated
|
||||
- Tests
|
||||
- TestHelpers
|
||||
- Fixtures
|
||||
|
||||
args:
|
||||
autoMockableImports: ["BitwardenKit", "BitwardenSdk", "Combine"]
|
||||
autoMockableTestableImports: ["BitwardenShared"]
|
||||
1
Mintfile
1
Mintfile
@ -3,3 +3,4 @@ nicklockwood/SwiftFormat@0.56.4
|
||||
SwiftGen/SwiftGen@6.6.3
|
||||
realm/SwiftLint@0.59.1
|
||||
yonaskolb/xcodegen@2.43.0
|
||||
krzysztofzablocki/Sourcery@2.2.7
|
||||
|
||||
136
Sourcery/Templates/AutoMockable.stencil
Normal file
136
Sourcery/Templates/AutoMockable.stencil
Normal file
@ -0,0 +1,136 @@
|
||||
// swiftlint:disable line_length
|
||||
// swiftlint:disable variable_name
|
||||
|
||||
import Foundation
|
||||
|
||||
{% for import in argument.autoMockableImports %}
|
||||
import {{ import }}
|
||||
{% endfor %}
|
||||
|
||||
{% for import in argument.autoMockableTestableImports %}
|
||||
@testable import {{ import }}
|
||||
{% endfor %}
|
||||
|
||||
{% macro swiftifyMethodName name %}{{ name | replace:"(","_" | replace:")","" | replace:":","_" | replace:"`","" | snakeToCamelCase | lowerFirstWord }}{% endmacro %}
|
||||
|
||||
{% macro methodThrowableErrorDeclaration method %}
|
||||
var {% call swiftifyMethodName method.selectorName %}Error: Error?
|
||||
{% endmacro %}
|
||||
|
||||
{% macro methodThrowableErrorUsage method %}
|
||||
if let error = {% call swiftifyMethodName method.selectorName %}Error {
|
||||
throw error
|
||||
}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro methodReceivedParameters method %}
|
||||
{%if method.parameters.count == 1 %}
|
||||
{% set receivedVarName %}{% call swiftifyMethodName method.selectorName %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }}{% endfor %}{% endset %}
|
||||
{{ receivedVarName }}{% for param in method.parameters %} = {{ param.name }}{% endfor %}
|
||||
{% call swiftifyMethodName method.selectorName %}ReceivedInvocations.append({{ receivedVarName }}!)
|
||||
{% else %}
|
||||
{% if not method.parameters.count == 0 %}
|
||||
{% set receivedVarName %}{% call swiftifyMethodName method.selectorName %}ReceivedArguments{% endset %}
|
||||
{{ receivedVarName }} = ({% for param in method.parameters %}{{ param.name }}: {{ param.name }}{% if not forloop.last%}, {% endif %}{% endfor %}){% if method.isGeneric %} as? ({% for param in method.parameters %}{{ param.name }}: {% call parameterType param %}{% if not forloop.last%}, {% endif %}{% endfor %}){% endif %}
|
||||
{% call swiftifyMethodName method.selectorName %}ReceivedInvocations.append({{ receivedVarName }}!)
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro methodReturnType method %}{% if method.returnTypeName.isVoid %}Void{% elif method.annotations["GenericReturn"] %}{{ method.annotations["GenericReturn"] }}{% else %}{{ method.returnTypeName }}{% endif %}{% endmacro %}
|
||||
|
||||
{% macro parameterType param %}{% if param.annotations["Generic"] %}{{ param.annotations["Generic"] }}{% else %}{{ param.unwrappedTypeName if param.typeAttributes.escaping else param.typeName }}{% endif %}{% endmacro %}
|
||||
{% macro parameterArguments param %}{% if param.typeAttributes.escaping %}@escaping {% endif %}{% endmacro %}
|
||||
|
||||
{% macro callClosure method %}return {{ 'try ' if method.throws }}{% if method.isGeneric %}({% endif %}{% call methodClosureName method %}.map({ {{ 'try ' if method.throws }}$0({% call methodClosureCallParameters method %}) }) ?? {% call swiftifyMethodName method.selectorName %}ReturnValue{% if method.isGeneric %}) as! {{ method.returnTypeName }}{% endif %}{% endmacro %}
|
||||
{% macro methodClosureName method %}{% call swiftifyMethodName method.selectorName %}Closure{% endmacro %}
|
||||
|
||||
{% macro methodClosureDeclaration method %}
|
||||
var {% call methodClosureName method %}: (({% for param in method.parameters %}{% call parameterArguments param %}{% call parameterType param %}{% if not forloop.last %}, {% endif %}{% endfor %}) {% if method.throws %}throws {% endif %}-> {% if method.isInitializer %}Void{% else %}{% call methodReturnType method %}{% endif %})?
|
||||
{% endmacro %}
|
||||
|
||||
{% macro methodClosureCallParameters method %}{% for param in method.parameters %}{{ param.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endmacro %}
|
||||
{% macro methodClosureCallParametersFromArguments method %}{% for param in method.parameters %}{% call receivedArgumentsVarName method %}!{% if method.parameters.count > 1 %}.{{ param.name }}{% if not forloop.last %}, {% endif %}{% endif %}{% endfor %}{% endmacro %}
|
||||
|
||||
{% macro receivedArgumentsVarName method %}{% if method.parameters.count == 1 %}{% call swiftifyMethodName method.selectorName %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }}{% endfor %}{% else %}{% call swiftifyMethodName method.selectorName %}ReceivedArguments{% endif %}{% endmacro %}
|
||||
|
||||
{% macro mockMethod method %}
|
||||
//MARK: - {{ method.shortName }}
|
||||
|
||||
{% if method.throws %}
|
||||
{% call methodThrowableErrorDeclaration method %}
|
||||
{% endif %}
|
||||
{% if not method.isInitializer %}
|
||||
var {% call swiftifyMethodName method.selectorName %}CalledCount = 0
|
||||
var {% call swiftifyMethodName method.selectorName %}Called: Bool {
|
||||
return {% call swiftifyMethodName method.selectorName %}CalledCount > 0
|
||||
}
|
||||
{% endif %}
|
||||
{% if method.parameters.count == 1 %}
|
||||
var {% call swiftifyMethodName method.selectorName %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }}: {{ '(' if param.isClosure }}{{ param.typeName.unwrappedTypeName }}{{ ')' if param.isClosure }}?{% endfor %}
|
||||
var {% call swiftifyMethodName method.selectorName %}ReceivedInvocations{% for param in method.parameters %}: [{{ '(' if param.isClosure }}{{ param.typeName.unwrappedTypeName }}{{ ')' if param.isClosure }}{%if param.typeName.isOptional%}?{%endif%}]{% endfor %} = []
|
||||
{% elif not method.parameters.count == 0 %}
|
||||
var {% call swiftifyMethodName method.selectorName %}ReceivedArguments: ({% for param in method.parameters %}{{ param.name }}: {% call parameterType param %}{{ ', ' if not forloop.last }}{% endfor %})?
|
||||
var {% call swiftifyMethodName method.selectorName %}ReceivedInvocations: [({% for param in method.parameters %}{{ param.name }}: {% call parameterType param %}{{ ', ' if not forloop.last }}{% endfor %})] = []
|
||||
{% endif %}
|
||||
{% if not method.returnTypeName.isVoid and not method.isInitializer %}
|
||||
var {% call swiftifyMethodName method.selectorName %}ReturnValue: {% call methodReturnType method %}{{ '!' if not method.isOptionalReturnType }}
|
||||
{% endif %}
|
||||
{% call methodClosureDeclaration method %}
|
||||
|
||||
{% if method.isInitializer %}
|
||||
required {{ method.name }} {
|
||||
{% call methodReceivedParameters method %}
|
||||
{% call methodClosureName method %}?({% call methodClosureCallParametersFromArguments method %})
|
||||
}
|
||||
{% else %}
|
||||
func {{ method.name }}{{ ' throws' if method.throws }}{% if not method.returnTypeName.isVoid %} -> {{ method.returnTypeName }}{% endif %} {
|
||||
{% if method.throws %}
|
||||
{% call methodThrowableErrorUsage method %}
|
||||
{% endif %}
|
||||
{% call swiftifyMethodName method.selectorName %}CalledCount += 1
|
||||
{% call methodReceivedParameters method %}
|
||||
{% if method.returnTypeName.isVoid %}
|
||||
{% if method.throws %}try {% endif %}{% call methodClosureName method %}?({% call methodClosureCallParametersFromArguments method %})
|
||||
{% else %}
|
||||
{% call callClosure method %}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro mockOptionalVariable variable %}
|
||||
var {% call mockedVariableName variable %}: {{ variable.typeName }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro mockNonOptionalArrayOrDictionaryVariable variable %}
|
||||
var {% call mockedVariableName variable %}: {{ variable.typeName }} = {% if variable.isArray %}[]{% elif variable.isDictionary %}[:]{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro mockNonOptionalVariable variable %}
|
||||
var {% call mockedVariableName variable %}: {{ variable.typeName }} {
|
||||
get {
|
||||
return {% call underlyingMockedVariableName variable %}
|
||||
}
|
||||
set(value) {
|
||||
{% call underlyingMockedVariableName variable %} = value
|
||||
}
|
||||
}
|
||||
var {% call underlyingMockedVariableName variable %}: {{ variable.typeName }}!
|
||||
{% endmacro %}
|
||||
|
||||
{% macro underlyingMockedVariableName variable %}underlying{{ variable.name|upperFirstLetter }}{% endmacro %}
|
||||
{% macro mockedVariableName variable %}{{ variable.name }}{% endmacro %}
|
||||
|
||||
{% for type in types.protocols where type.based.AutoMockable or type|annotated:"AutoMockable" %}{% if type.name != "AutoMockable" %}
|
||||
class Mock{{ type.name }}: {{ type.name }} {
|
||||
{% for variable in type.allVariables|!definedInExtension %}
|
||||
{% if variable.isOptional %}{% call mockOptionalVariable variable %}{% elif variable.isArray or variable.isDictionary %}{% call mockNonOptionalArrayOrDictionaryVariable variable %}{% else %}{% call mockNonOptionalVariable variable %}{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% for method in type.allMethods|!definedInExtension %}
|
||||
{% call mockMethod method %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}{% endfor %}
|
||||
@ -174,6 +174,8 @@ targets:
|
||||
- "**/TestHelpers/*"
|
||||
- "**/Fixtures/*"
|
||||
- "**/__Snapshots__/*"
|
||||
- "**/Sourcery/Generated/*"
|
||||
- "**/sourcery.yml"
|
||||
- path: AuthenticatorShared
|
||||
includes:
|
||||
- "**/__Snapshots__/*"
|
||||
@ -184,6 +186,8 @@ targets:
|
||||
optional: true
|
||||
- path: AuthenticatorShared/Core/Vault/Services/Importers/Support/Generated/GoogleAuth.pb.swift
|
||||
optional: true
|
||||
- path: AuthenticatorShared/Sourcery/sourcery.yml
|
||||
buildPhase: none
|
||||
dependencies:
|
||||
- target: BitwardenKit/AuthenticatorBridgeKit
|
||||
- package: BitwardenSdk
|
||||
@ -210,6 +214,15 @@ targets:
|
||||
$SRCROOT/AuthenticatorShared/Core/Vault/Services/Importers/Support/GoogleAuth.proto
|
||||
outputFiles:
|
||||
- $(SRCROOT)/AuthenticatorShared/Core/Vault/Services/Importers/Support/Generated/GoogleAuth.pb.swift
|
||||
- name: Sourcery
|
||||
script: |
|
||||
if [[ ! "$PATH" =~ "/opt/homebrew/bin" ]]; then
|
||||
PATH="/opt/homebrew/bin:$PATH"
|
||||
fi
|
||||
mint run sourcery --config AuthenticatorShared/Sourcery/sourcery.yml
|
||||
basedOnDependencyAnalysis: false
|
||||
outputFiles:
|
||||
- $(SRCROOT)/AuthenticatorShared/Sourcery/Generated/AutoMockable.generated.swift
|
||||
AuthenticatorSharedTests:
|
||||
type: bundle.unit-test
|
||||
platform: iOS
|
||||
@ -225,6 +238,10 @@ targets:
|
||||
- "**/TestHelpers/*"
|
||||
- "**/Fixtures/*"
|
||||
- path: GlobalTestHelpers-bwa
|
||||
- path: AuthenticatorShared/Sourcery/Generated
|
||||
optional: true
|
||||
- path: AuthenticatorShared/Sourcery/Generated/AutoMockable.generated.swift
|
||||
optional: true
|
||||
dependencies:
|
||||
- target: Authenticator
|
||||
- target: AuthenticatorShared
|
||||
|
||||
@ -362,6 +362,8 @@ targets:
|
||||
- "**/TestHelpers/*"
|
||||
- "**/Fixtures/*"
|
||||
- "**/__Snapshots__/*"
|
||||
- "**/Sourcery/Generated/*"
|
||||
- "**/sourcery.yml"
|
||||
- path: BitwardenShared
|
||||
includes:
|
||||
- "**/__Snapshots__/*"
|
||||
@ -373,6 +375,8 @@ targets:
|
||||
- path: BitwardenShared/UI/Platform/Application/Support/Generated/Localizations.swift
|
||||
optional: true
|
||||
- path: BitwardenWatchShared
|
||||
- path: BitwardenShared/Sourcery/sourcery.yml
|
||||
buildPhase: none
|
||||
dependencies:
|
||||
- package: BitwardenSdk
|
||||
- package: SwiftUIIntrospect
|
||||
@ -391,6 +395,15 @@ targets:
|
||||
- $(SRCROOT)/BitwardenShared/UI/Platform/Application/Support/Generated/Assets.swift
|
||||
- $(SRCROOT)/BitwardenShared/UI/Platform/Application/Support/Generated/Fonts.swift
|
||||
- $(SRCROOT)/BitwardenShared/UI/Platform/Application/Support/Generated/Localizations.swift
|
||||
- name: Sourcery
|
||||
script: |
|
||||
if [[ ! "$PATH" =~ "/opt/homebrew/bin" ]]; then
|
||||
PATH="/opt/homebrew/bin:$PATH"
|
||||
fi
|
||||
mint run sourcery --config BitwardenShared/Sourcery/sourcery.yml
|
||||
basedOnDependencyAnalysis: false
|
||||
outputFiles:
|
||||
- $(SRCROOT)/BitwardenShared/Sourcery/Generated/AutoMockable.generated.swift
|
||||
BitwardenSharedTests:
|
||||
type: bundle.unit-test
|
||||
platform: iOS
|
||||
@ -409,6 +422,10 @@ targets:
|
||||
- "**/TestHelpers/*"
|
||||
- "**/Fixtures/*"
|
||||
- path: GlobalTestHelpers
|
||||
- path: BitwardenShared/Sourcery/Generated
|
||||
optional: true
|
||||
- path: BitwardenShared/Sourcery/Generated/AutoMockable.generated.swift
|
||||
optional: true
|
||||
dependencies:
|
||||
- target: Bitwarden
|
||||
- target: BitwardenShared
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user