ZcashLightClientKit/Tests/TestUtils/Sourcery/AutoMockable.stencil

166 lines
10 KiB
Plaintext
Raw Normal View History

[#888] Make actor from ZcashRustBackendWelding Closes #888. - `ZcashRustBackend` is actor now. So majority of methods in this actor are now async. - Some methods stayed `static` in `ZcashRustBackend`. It would be hard to pass instance of the `ZcashRustBackend` to the places where these methods are used in static manner. And it would change lot of APIs. But it isn't problem from technical perspective because these methods would be `nonisolated` otherwise. - Methods `lastError()` and `getLastError()` in `ZcashRustBackend` are now private. This makes sure that ther won't be aby race condition between other methods and these two error methods. - All the methods for which was `lastError()` used in code now throw error. So `lastError()` is no longer needed outside of the `ZcashRustBackend`. - There are in the public API related to `DerivationTool`. - `DerivationTool` now requires instance of the `ZcashRustBackend`. And `ZcashRustBackend` isn't public type. So `DerivationTool` doesn't have any public constructor now. It can be created only via `Initializer.makeDerivationTool()` instance method. - `deriveUnifiedSpendingKey()` and `deriveUnifiedFullViewingKey()` in `DerivationTool` are now async. It is because these are using `ZcashRustBackend` inside. `DerivationTool` offers alternative (closure and combine) APIs. But downside is that there is no sync API to dervie spending key or viewing key. - Some methods of the `DerivationTool` are now static. These methods don't use anything that requires instance of the `DerivationTool` inside. [#888] Use Sourcery to generate mocks - I wrote mock for `Synchronizer` manually. And it's tedious and long and boring work. - Now `ZcashRustBackendWelding` is changed a lot so it means `MockRustBackend` must be changed a lot. So I decided to introduce `sourcery` to generate mocks from protocols so we don't have to do it manually ever. - To generate mocks go to `ZcashLightClientKit/Tests/TestUtils/Sourcery` directory and run `generateMocks.sh` script. - Your protocol must be mentioned in `AutoMockable.swift` file. Generated mocks are in `AutoMockable.generated.swift` file. [#888] Fix Offline tests - Offline tests target now runs and tests are green. - There is log of changes in tests. But logic is not changed. - Updated `AutoMockable.stencil` so sourcery is able to generate mock as actor when protocol is marked with: `// sourcery: mockActor`. - Last few updates in `ZcashRustBackendWelding`. In previous PR `rewindCacheToHeight` methods was overlooked and it didn't throw error. - Removed `MockRustBackend` and using generated `ZCashRustBackendWeldingMock` instead. - Using generated `SynchronizerMock`. [#888] Fix NetworkTests - Changed a bit how rust backend mock is used in the tests. Introduced `RustBackendMockHelper`. There are some state variables that must be preserved within one instance of the mock. This helper does exactly this. It keeps this state variables in the memory and helping mock to work as expected. [#888] Fix Darkside tests Create ZcashKeyDeriving internal protocol Use New DerivationTool that does not require RustBackend Remove duplicated methods that had been copied over [#888] Fix potentially broken tests I broke the tests because I moved `testTempDirectory` from each `TestCase` to the `Environment`. By this I caused that each tests uses exactly same URL. Which is directly against purpose of `testTempDirectory`. So now each test calls this one and store it to local variable. So each test has unique URL. [#888] Add ability to mock nonisolated methods to AutoMockable.stencil [#888] Add changelog and fix the documentation in ZcashRustBackendWelding [#888] Rename derivation rust backend protocol and remove static methods - Renamed `ZcashKeyDeriving` to `ZcashKeyDerivationBackendWelding`. So the naming scheme is same as for `ZcashRustBackendWelding`. - `ZcashKeyDerivationBackend` is now struct instead of enum. - Methods in `ZcashKeyDerivationBackendWelding` (except one) are no longer static. Because of this the respective methods in `DerivationTool` aren't also static anymore.
2023-03-31 10:10:35 -07:00
import Combine
@testable import ZcashLightClientKit
{% macro methodName method%}{%if method|annotated:"mockedName" %}{{ method.annotations.mockedName }}{% else %}{% call swiftifyMethodName method.selectorName %}{% endif %}{% endmacro %}
{% macro swiftifyMethodName name %}{{ name | replace:"(","_" | replace:")","" | replace:":","_" | replace:"`","" | snakeToCamelCase | lowerFirstWord }}{% endmacro %}
{% macro methodNameUpper method%}{%if method|annotated:"mockedName" %}{{ method.annotations.mockedName }}{% else %}{% call swiftifyMethodNameUpper method.selectorName %}{% endif %}{% endmacro %}
{% macro swiftifyMethodNameUpper name %}{{ name | replace:"(","_" | replace:")","" | replace:":","_" | replace:"`","" | snakeToCamelCase | upperFirstLetter }}{% endmacro %}
{% macro methodThrowableErrorDeclaration method type %}
{% if method.isStatic %}static {% endif %}var {% call methodName method %}ThrowableError: Error?
{% call methodMockPropertySetter method type "ThrowableError" "Error?" %}
{% endmacro %}
{% macro methodMockPropertySetter method type postfix propertyType %}
{% if type|annotated:"mockActor" %}{% if not method.isStatic %}
func set{% call methodNameUpper method %}{{ postfix }}(_ param: {{ propertyType }}) async {
{% call methodName method %}{{ postfix }} = param
}
{% endif %}{% endif %}
{% endmacro %}
{% macro methodThrowableErrorUsage method %}
if let error = {% if method.isStatic %}Self.{% endif %}{% call methodName method %}ThrowableError {
throw error
}
{% endmacro %}
{% macro methodReceivedParameters method %}
{%if method.parameters.count == 1 %}
{% if method.isStatic %}Self.{% endif %}{% call methodName method %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }} = {{ param.name }}{% endfor %}
{% else %}
{% if not method.parameters.count == 0 %}
{% if method.isStatic %}Self.{% endif %}{% call methodName method %}ReceivedArguments = ({% for param in method.parameters %}{{ param.name }}: {{ param.name }}{% if not forloop.last%}, {% endif %}{% endfor %})
{% endif %}
{% endif %}
{% endmacro %}
{% macro methodClosureName method %}{% call methodName method %}Closure{% endmacro %}
{% macro paramTypeName param, method %}{% if method.annotations[param.name] %}{{method.annotations[param.name]}}{% else %}{{ param.typeName }}{% endif %}{% endmacro %}
{% macro unwrappedParamTypeName param, method %}{% if method.annotations[param.name] %}{{method.annotations[param.name]}}{% else %}{{ param.typeName.unwrappedTypeName }}{% endif %}{% endmacro %}
{% macro closureType method type %}({% for param in method.parameters %}{% call paramTypeName param, method %}{% if not forloop.last %}, {% endif %}{% endfor %}) {% if method.isAsync %}async {% endif %}{% if method.throws %}throws {% endif %}-> {% if method.isInitializer %}Void{% else %}{{ method.returnTypeName }}{% endif %}{% endmacro %}
{% macro methodClosureDeclaration method type %}
{% if method.isStatic %}static {% endif %}var {% call methodClosureName method %}: ({% call closureType method type %})?
{% if type|annotated:"mockActor" %}{% if not method.isStatic %}
func set{% call methodNameUpper method %}Closure(_ param: ({% call closureType method type %})?) async {
{% call methodName method %}Closure = param
}
{% endif %}{% endif %}
{% endmacro %}
{% macro methodClosureCallParameters method %}{% for param in method.parameters %}{{ param.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endmacro %}
{% macro mockMethod method type %}
{% if method|!annotated:"skipAutoMock" %}
// MARK: - {{ method.shortName }}
{% if ((type|annotated:"mockActor") and (method.isAsync) or (method.isStatic)) or (not type|annotated:"mockActor") %}
{% if method.throws %}
{% call methodThrowableErrorDeclaration method type %}
{% endif %}
{% if not method.isInitializer %}
{% if method.isStatic %}static {% endif %}var {% call methodName method %}CallsCount = 0
{% if method.isStatic %}static {% endif %}var {% call methodName method %}Called: Bool {
return {% if method.isStatic %}Self.{% endif %}{% call methodName method %}CallsCount > 0
}
{% endif %}
{% if method.parameters.count == 1 %}
{% if method.isStatic %}static {% endif %}var {% call methodName method %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }}: {% if param.isClosure %}({% endif %}{% call unwrappedParamTypeName param, method %}{% if param.isClosure %}){% endif %}?{% endfor %}
{% else %}{% if not method.parameters.count == 0 %}
{% if method.isStatic %}static {% endif %}var {% call methodName method %}ReceivedArguments: ({% for param in method.parameters %}{{ param.name }}: {% if param.typeAttributes.escaping %}{% call unwrappedParamTypeName param, method %}{% else %}{% call paramTypeName param, method %}{% endif %}{% if not forloop.last %}, {% endif %}{% endfor %})?
{% endif %}{% endif %}
{% if not method.returnTypeName.isVoid and not method.isInitializer %}
{% if method.isStatic %}static {% endif %}var {% call methodName method %}ReturnValue: {{ method.returnTypeName }}{{ '!' if not method.isOptionalReturnType }}
{% call methodMockPropertySetter method type "ReturnValue" method.returnTypeName %}
{% endif %}
{% call methodClosureDeclaration method type %}
{% endif %}
{% if method.isInitializer %}
required {{ method.name }} {
{% call methodReceivedParameters method %}
{% call methodClosureName method %}?({% call methodClosureCallParameters method %})
}
{% else %}
{% if (not method.isAsync) and (not method.isStatic) and (type|annotated:"mockActor") %}nonisolated {% endif %}{% if method.isStatic %}static {% endif %}func {{ method.name }}{% if method.isAsync %} async{% endif %}{% if method.throws %} throws{% endif %}{% if not method.returnTypeName.isVoid %} -> {{ method.returnTypeName }}{% endif %} {
{% if ((type|annotated:"mockActor") and ((method.isAsync) or (method.isStatic))) or (not type|annotated:"mockActor") %}
{% if method.throws %}
{% call methodThrowableErrorUsage method %}
{% endif %}
{% if method.isStatic %}Self.{% endif %}{% call methodName method %}CallsCount += 1
{% call methodReceivedParameters method %}
{% if method.returnTypeName.isVoid %}
{% if method.throws %}try {% endif %}{% if method.isAsync %}await {% endif %}{% call methodClosureName method %}?({% call methodClosureCallParameters method %})
{% else %}
if let closure = {% if method.isStatic %}Self.{% endif %}{% call methodClosureName method %} {
return {% if method.throws %}try {% endif %}{% if method.isAsync %}await {% endif %}closure({% call methodClosureCallParameters method %})
} else {
return {% if method.isStatic %}Self.{% endif %}{% call methodName method %}ReturnValue
}
{% endif %}
{% else %}
{% if method.throws %}try {% endif %}{% call methodClosureName method %}!({% call methodClosureCallParameters method %})
{% endif %}
}
{% endif %}
{% endif %}
{% endmacro %}
{% macro mockOptionalVariable variable %}
var {% call mockedVariableName variable %}: {{ variable.typeName }}
{% endmacro %}
{% macro mockNonOptionalArrayOrDictionaryVariable variable %}
var {% call mockedVariableName variable %}: {{ variable.typeName }} {
get{% if variable.isAsync %} async{% endif %} { return {% call underlyingMockedVariableName variable %} }
}
var {% call underlyingMockedVariableName 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 %} }
}
var {% call underlyingMockedVariableName variable %}: {% if variable.typeName.isClosure %}({{ variable.typeName }})!{% else %}{{ variable.typeName }}!{% endif %}
{% endmacro %}
{% macro underlyingMockedVariableName variable %}underlying{{ variable.name|upperFirstLetter }}{% endmacro %}
{% macro initialMockedVariableValue variable %}initial{{ variable.name|upperFirstLetter }}{% endmacro %}
{% macro mockedVariableName variable %}{{ variable.name }}{% endmacro %}
// MARK: - AutoMockable protocols
{% for type in types.protocols where type.based.AutoMockable or type|annotated:"AutoMockable" %}{% if type.name != "AutoMockable" %}
{% if type|annotated:"moduleName" %}
/// Imported from {{ type.annotations.moduleName }} module
{% endif %}
{% if type|annotated:"targetOS" %}
#if os({{ type.annotations.targetOS }})
{% endif %}
{% if type|annotated:"mockActor" %}actor {% else %}class {% endif %}{{ type.name }}Mock: {% if type|annotated:"baseClass" %}{{ type.annotations.baseClass }}, {% endif %}{% if type|annotated:"moduleName" %}{{ type.annotations.moduleName }}.{% endif %}{{ type.name }} {
{% for method in type.allMethods|!definedInExtension %}
{% if (not method.isAsync) and (not method.isStatic) and (type|annotated:"mockActor") %}
nonisolated let {% call methodName method %}Closure: ({% call closureType method type %})?
{% endif %}
{% endfor %}
init(
{% for method in type.allMethods|!definedInExtension where ((not method.isAsync) and (not method.isStatic) and (type|annotated:"mockActor")) %}
{% call methodName method %}Closure: ({% call closureType method type %})? = nil{% if not forloop.last %},{% endif %}
{% endfor %}
) {
{% for method in type.allMethods|!definedInExtension %}
{% if (not method.isAsync) and (not method.isStatic) and (type|annotated:"mockActor") %}
self.{% call methodName method %}Closure = {% call methodName method %}Closure
{% endif %}
{% endfor %}
}
{% for variable in type.allVariables|!definedInExtension %}
{% if variable|!annotated:"skipAutoMock" %}
{% if variable.isOptional %}{% call mockOptionalVariable variable %}
{% elif variable.isArray or variable.isDictionary %}{% call mockNonOptionalArrayOrDictionaryVariable variable %}
{% else %}{% call mockNonOptionalVariable variable %}
{% endif %}
{% endif %}
{% endfor %}
{% for method in type.allMethods|!definedInExtension %}
{% call mockMethod method type %}
{% endfor %}
}
{% if type|annotated:"targetOS" %}
#endif
{% endif %}
{% endif %}{% endfor %}