mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 03:06:37 +00:00
fb49f5b83b
Add the element-call-ios dependency and a developer option for native calls The package carries the call UI and the matrix-rust-rtc media stack, pinned by exact version the way the SDK is, with the local path kept commented out for working against a checkout. Its media xcframework has no Intel simulator slice and a package cannot say so for the projects that consume it, hence the excluded architecture at the project level. The developer option is off by default and nothing reads it yet. It is placed next to the Element Call URL override, which only applies to the web view that native calls replace.
238 lines
19 KiB
Plaintext
238 lines
19 KiB
Plaintext
// swiftlint:disable all
|
|
@preconcurrency import Combine
|
|
@preconcurrency import SwiftUI
|
|
|
|
@preconcurrency import MatrixRustSDK
|
|
|
|
import AnalyticsEvents
|
|
import AVFoundation
|
|
import CallKit
|
|
import ElementCall
|
|
import Foundation
|
|
import LocalAuthentication
|
|
import Photos
|
|
|
|
{% 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 accessLevel level %}{% if level != 'internal' %}{{ level }} {% endif %}{% endmacro %}
|
|
{% macro staticSpecifier method %}{% if method.isStatic and not method.isInitializer %}static {% endif %}{% endmacro %}
|
|
{% macro methodThrowableErrorDeclaration method %}
|
|
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}nonisolated(unsafe) var {% call swiftifyMethodName method.selectorName %}ThrowableError: Error?
|
|
{% endmacro %}
|
|
{% macro methodThrowableErrorUsage method %}
|
|
if let error = {% call swiftifyMethodName method.selectorName %}ThrowableError {
|
|
throw error
|
|
}
|
|
{% endmacro %}
|
|
{% macro methodReceivedParameters method %}
|
|
{% set hasNonEscapingClosures %}
|
|
{%- for param in method.parameters where param.isClosure and not param.typeAttributes.escaping %}
|
|
{{ true }}
|
|
{% endfor -%}
|
|
{% endset %}
|
|
{% if method.parameters.count == 1 and not hasNonEscapingClosures %}
|
|
{% call swiftifyMethodName method.selectorName %}Received{% for param in method.parameters %}{{ param.name | replace:"`","" | upperFirstLetter }} = {{ param.name | replace:"`","" }}{% endfor %}
|
|
{% call swiftifyMethodName method.selectorName %}ReceivedInvocationsLock.withLock { {% call swiftifyMethodName method.selectorName %}UnderlyingReceivedInvocations.append({% for param in method.parameters %}{{ param.name }}){% endfor %} }
|
|
{% else %}
|
|
{% if not method.parameters.count == 0 and not hasNonEscapingClosures %}
|
|
{% call swiftifyMethodName method.selectorName %}ReceivedArguments = ({% for param in method.parameters %}{{ param.name | replace:"`","" }}: {{ param.name | replace:"`","" }}{% if not forloop.last%}, {% endif %}{% endfor %})
|
|
{% call swiftifyMethodName method.selectorName %}ReceivedInvocationsLock.withLock { {% call swiftifyMethodName method.selectorName %}UnderlyingReceivedInvocations.append(({% for param in method.parameters %}{{ param.name | replace:"`","" }}: {{ param.name | replace:"`","" }}{% if not forloop.last%}, {% endif %}{% endfor %})) }
|
|
{% endif %}
|
|
{% endif %}
|
|
{% endmacro %}
|
|
{% macro methodClosureName method %}{% call swiftifyMethodName method.selectorName %}Closure{% endmacro %}
|
|
{% macro closureReturnTypeName method %}{% if method.isOptionalReturnType %}{{ method.unwrappedReturnTypeName }}?{% else %}{{ method.returnTypeName }}{% endif %}{% endmacro %}
|
|
{% macro methodClosureDeclaration method %}
|
|
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}nonisolated(unsafe) var {% call methodClosureName method %}: (({% for param in method.parameters %}{{ param.typeName }}{% if not forloop.last %}, {% endif %}{% endfor %}) {% if method.isAsync %}async {% endif %}{% if method.throws %}throws {% endif %}-> {% if method.isInitializer %}Void{% else %}{% call closureReturnTypeName method %}{% endif %})?
|
|
{% endmacro %}
|
|
{% macro methodClosureCallParameters method %}{% for param in method.parameters %}{{ param.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endmacro %}
|
|
{% macro mockMethod method %}
|
|
//MARK: - {{ method.shortName }}
|
|
|
|
{% if method.throws %}
|
|
{% call methodThrowableErrorDeclaration method %}
|
|
{% endif %}
|
|
{% if not method.isInitializer %}
|
|
private {% call staticSpecifier method %}let {% call swiftifyMethodName method.selectorName %}CallsCountLock = NSLock()
|
|
private {% call staticSpecifier method %}nonisolated(unsafe) var {% call swiftifyMethodName method.selectorName %}UnderlyingCallsCount = 0
|
|
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}CallsCount: Int {
|
|
get { {% call swiftifyMethodName method.selectorName %}CallsCountLock.withLock { {% call swiftifyMethodName method.selectorName %}UnderlyingCallsCount } }
|
|
set { {% call swiftifyMethodName method.selectorName %}CallsCountLock.withLock { {% call swiftifyMethodName method.selectorName %}UnderlyingCallsCount = newValue } }
|
|
}
|
|
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}Called: Bool {
|
|
return {% call swiftifyMethodName method.selectorName %}CallsCount > 0
|
|
}
|
|
{% endif %}
|
|
{% set hasNonEscapingClosures %}
|
|
{%- for param in method.parameters where param.isClosure and not param.typeAttributes.escaping %}
|
|
{{ true }}
|
|
{% endfor -%}
|
|
{% endset %}
|
|
{% if method.parameters.count == 1 and not hasNonEscapingClosures %}
|
|
private {% call staticSpecifier method %}let {% call swiftifyMethodName method.selectorName %}Received{% for param in method.parameters %}{{ param.name| replace:"`","" | upperFirstLetter }}Lock = NSLock(){% endfor %}
|
|
private {% call staticSpecifier method %}nonisolated(unsafe) var {% call swiftifyMethodName method.selectorName %}UnderlyingReceived{% for param in method.parameters %}{{ param.name| replace:"`","" | upperFirstLetter }}: {{ '(' if param.isClosure }}{{ param.typeName.unwrappedTypeName }}{{ ')' if param.isClosure }}?{% endfor %}
|
|
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}Received{% for param in method.parameters %}{{ param.name| replace:"`","" | upperFirstLetter }}: {{ '(' if param.isClosure }}{{ param.typeName.unwrappedTypeName }}{{ ')' if param.isClosure }}?{% endfor %} {
|
|
get { {% for param in method.parameters %}{% call swiftifyMethodName method.selectorName %}Received{{ param.name| replace:"`","" | upperFirstLetter }}Lock{% endfor %}.withLock { {% for param in method.parameters %}{% call swiftifyMethodName method.selectorName %}UnderlyingReceived{{ param.name| replace:"`","" | upperFirstLetter }}{% endfor %} } }
|
|
set { {% for param in method.parameters %}{% call swiftifyMethodName method.selectorName %}Received{{ param.name| replace:"`","" | upperFirstLetter }}Lock{% endfor %}.withLock { {% for param in method.parameters %}{% call swiftifyMethodName method.selectorName %}UnderlyingReceived{{ param.name| replace:"`","" | upperFirstLetter }}{% endfor %} = newValue } }
|
|
}
|
|
private {% call staticSpecifier method %}let {% call swiftifyMethodName method.selectorName %}ReceivedInvocationsLock = NSLock()
|
|
private {% call staticSpecifier method %}nonisolated(unsafe) var {% call swiftifyMethodName method.selectorName %}UnderlyingReceivedInvocations{% for param in method.parameters %}: [{{ '(' if param.isClosure }}{{ param.typeName.unwrappedTypeName }}{{ ')' if param.isClosure }}{%if param.typeName.isOptional%}?{%endif%}]{% endfor %} = []
|
|
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}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 %} {
|
|
get { {% call swiftifyMethodName method.selectorName %}ReceivedInvocationsLock.withLock { {% call swiftifyMethodName method.selectorName %}UnderlyingReceivedInvocations } }
|
|
set { {% call swiftifyMethodName method.selectorName %}ReceivedInvocationsLock.withLock { {% call swiftifyMethodName method.selectorName %}UnderlyingReceivedInvocations = newValue } }
|
|
}
|
|
{% elif not method.parameters.count == 0 and not hasNonEscapingClosures %}
|
|
private {% call staticSpecifier method %}let {% call swiftifyMethodName method.selectorName %}ReceivedArgumentsLock = NSLock()
|
|
private {% call staticSpecifier method %}nonisolated(unsafe) var {% call swiftifyMethodName method.selectorName %}UnderlyingReceivedArguments: ({% for param in method.parameters %}{{ param.name }}: {{ param.unwrappedTypeName if param.typeAttributes.escaping else param.typeName }}{{ ', ' if not forloop.last }}{% endfor %})?
|
|
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}ReceivedArguments: ({% for param in method.parameters %}{{ param.name }}: {{ param.unwrappedTypeName if param.typeAttributes.escaping else param.typeName }}{{ ', ' if not forloop.last }}{% endfor %})? {
|
|
get { {% call swiftifyMethodName method.selectorName %}ReceivedArgumentsLock.withLock { {% call swiftifyMethodName method.selectorName %}UnderlyingReceivedArguments } }
|
|
set { {% call swiftifyMethodName method.selectorName %}ReceivedArgumentsLock.withLock { {% call swiftifyMethodName method.selectorName %}UnderlyingReceivedArguments = newValue } }
|
|
}
|
|
private {% call staticSpecifier method %}let {% call swiftifyMethodName method.selectorName %}ReceivedInvocationsLock = NSLock()
|
|
private {% call staticSpecifier method %}nonisolated(unsafe) var {% call swiftifyMethodName method.selectorName %}UnderlyingReceivedInvocations: [({% for param in method.parameters %}{{ param.name }}: {{ param.unwrappedTypeName if param.typeAttributes.escaping else param.typeName }}{{ ', ' if not forloop.last }}{% endfor %})] = []
|
|
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}ReceivedInvocations: [({% for param in method.parameters %}{{ param.name }}: {{ param.unwrappedTypeName if param.typeAttributes.escaping else param.typeName }}{{ ', ' if not forloop.last }}{% endfor %})] {
|
|
get { {% call swiftifyMethodName method.selectorName %}ReceivedInvocationsLock.withLock { {% call swiftifyMethodName method.selectorName %}UnderlyingReceivedInvocations } }
|
|
set { {% call swiftifyMethodName method.selectorName %}ReceivedInvocationsLock.withLock { {% call swiftifyMethodName method.selectorName %}UnderlyingReceivedInvocations = newValue } }
|
|
}
|
|
{% endif %}
|
|
{% if not method.returnTypeName.isVoid and not method.isInitializer %}
|
|
|
|
private {% call staticSpecifier method %}let {% call swiftifyMethodName method.selectorName %}ReturnValueLock = NSLock()
|
|
private {% call staticSpecifier method %}nonisolated(unsafe) var {% call swiftifyMethodName method.selectorName %}UnderlyingReturnValue: {{ '(' if method.returnTypeName.isClosure and not method.isOptionalReturnType }}{{ method.returnTypeName }}{{ ')' if method.returnTypeName.isClosure and not method.isOptionalReturnType }}{{ '!' if not method.isOptionalReturnType }}
|
|
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}ReturnValue: {{ '(' if method.returnTypeName.isClosure and not method.isOptionalReturnType }}{{ method.returnTypeName }}{{ ')' if method.returnTypeName.isClosure and not method.isOptionalReturnType }}{{ '!' if not method.isOptionalReturnType }} {
|
|
get { {% call swiftifyMethodName method.selectorName %}ReturnValueLock.withLock { {% call swiftifyMethodName method.selectorName %}UnderlyingReturnValue } }
|
|
set { {% call swiftifyMethodName method.selectorName %}ReturnValueLock.withLock { {% call swiftifyMethodName method.selectorName %}UnderlyingReturnValue = newValue } }
|
|
}
|
|
{% endif %}
|
|
{% call methodClosureDeclaration method %}
|
|
|
|
{% if method.isInitializer %}
|
|
{% call accessLevel method.accessLevel %}required {{ method.name }} {
|
|
{% call methodReceivedParameters method %}
|
|
{% call methodClosureName method %}?({% call methodClosureCallParameters method %})
|
|
}
|
|
{% else %}
|
|
{% for name, attribute in method.attributes %}
|
|
{% for value in attribute %}
|
|
{{ value }}
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{# @concurrent keeps async mocks suspending like the real implementations would, otherwise with caller isolation inherited by default, intermediate states are never observable. #}
|
|
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}{{ '@concurrent ' if method.isAsync }}func {{ method.name }}{{ ' async' if method.isAsync }}{{ ' throws' if method.throws }}{% if not method.returnTypeName.isVoid %} -> {{ method.returnTypeName }}{% endif %} {
|
|
{% if method.throws %}
|
|
{% call methodThrowableErrorUsage method %}
|
|
{% endif %}
|
|
{% call swiftifyMethodName method.selectorName %}CallsCountLock.withLock { {% call swiftifyMethodName method.selectorName %}UnderlyingCallsCount += 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 {% call methodClosureName method %} = {% call methodClosureName method %} {
|
|
return {{ 'try ' if method.throws }}{{ 'await ' if method.isAsync }}{% call methodClosureName method %}({% call methodClosureCallParameters method %})
|
|
} else {
|
|
return {% call swiftifyMethodName method.selectorName %}ReturnValue
|
|
}
|
|
{% endif %}
|
|
}
|
|
{% endif %}
|
|
{% endmacro %}
|
|
{% macro resetMethod method %}
|
|
{# for type method which are mocked, a way to reset the invocation, argument, etc #}
|
|
{% if method.isStatic and not method.isInitializer %} //MARK: - {{ method.shortName }}
|
|
{% if not method.isInitializer %}
|
|
{% call swiftifyMethodName method.selectorName %}CallsCount = 0
|
|
{% endif %}
|
|
{% if method.parameters.count == 1 %}
|
|
{% call swiftifyMethodName method.selectorName %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }}{% endfor %} = nil
|
|
{% call swiftifyMethodName method.selectorName %}ReceivedInvocations = []
|
|
{% elif not method.parameters.count == 0 %}
|
|
{% call swiftifyMethodName method.selectorName %}ReceivedArguments = nil
|
|
{% call swiftifyMethodName method.selectorName %}ReceivedInvocations = []
|
|
{% endif %}
|
|
{% call methodClosureName method %} = nil
|
|
{% if method.throws %}
|
|
{% call swiftifyMethodName method.selectorName %}ThrowableError = nil
|
|
{% endif %}
|
|
|
|
{% endif %}
|
|
{% endmacro %}
|
|
{% macro mockOptionalVariable variable %}
|
|
{% if variable.name == 'delegate' %}weak {% endif %}{% call accessLevel variable.readAccess %}nonisolated(unsafe) var {% call mockedVariableName variable %}: {{ variable.typeName }}
|
|
{% endmacro %}
|
|
{% macro mockNonOptionalArrayOrDictionaryVariable variable %}
|
|
{% call accessLevel variable.readAccess %}nonisolated(unsafe) var {% call mockedVariableName variable %}: {{ variable.typeName }} = {% if variable.isArray %}[]{% elif variable.isDictionary %}[:]{% endif %}
|
|
{% endmacro %}
|
|
{% macro mockNonOptionalVariable variable %}
|
|
{% call accessLevel variable.readAccess %}var {% call mockedVariableName variable %}: {{ variable.typeName }} {
|
|
get { return {% call underlyingMockedVariableName variable %} }
|
|
set(value) { {% call underlyingMockedVariableName variable %} = value }
|
|
}
|
|
{% set wrappedTypeName %}{% if variable.typeName.isProtocolComposition %}({{ variable.typeName }}){% else %}{{ variable.typeName }}{% endif %}{% endset %}
|
|
{% call accessLevel variable.readAccess %}nonisolated(unsafe) var {% call underlyingMockedVariableName variable %}: {{ wrappedTypeName }}!
|
|
{% endmacro %}
|
|
{% macro variableThrowableErrorDeclaration variable %}
|
|
{% call accessLevel variable.readAccess %}nonisolated(unsafe) var {% call mockedVariableName variable %}ThrowableError: Error?
|
|
{% endmacro %}
|
|
{% macro variableThrowableErrorUsage variable %}
|
|
if let error = {% call mockedVariableName variable %}ThrowableError {
|
|
throw error
|
|
}
|
|
{% endmacro %}
|
|
{% macro variableClosureDeclaration variable %}
|
|
{% call accessLevel variable.readAccess %}nonisolated(unsafe) var {% call variableClosureName variable %}: (() {% if variable.isAsync %}async {% endif %}{% if variable.throws %}throws {% endif %}-> {{ variable.typeName }})?
|
|
{% endmacro %}
|
|
{% macro variableClosureName variable %}{% call mockedVariableName variable %}Closure{% endmacro %}
|
|
{% macro mockAsyncOrThrowingVariable variable %}
|
|
{% call accessLevel variable.readAccess %}nonisolated(unsafe) var {% call mockedVariableName variable %}CallsCount = 0
|
|
{% call accessLevel variable.readAccess %}var {% call mockedVariableName variable %}Called: Bool {
|
|
return {% call mockedVariableName variable %}CallsCount > 0
|
|
}
|
|
|
|
{% call accessLevel variable.readAccess %}var {% call mockedVariableName variable %}: {{ variable.typeName }} {
|
|
get {% if variable.isAsync %}async {% endif %}{% if variable.throws %}throws {% endif %}{
|
|
{% if variable.throws %}
|
|
{% call variableThrowableErrorUsage variable %}
|
|
{% endif %}
|
|
{% call mockedVariableName variable %}CallsCount += 1
|
|
if let {% call variableClosureName variable %} = {% call variableClosureName variable %} {
|
|
return {{ 'try ' if variable.throws }}{{ 'await ' if variable.isAsync }}{% call variableClosureName variable %}()
|
|
} else {
|
|
return {% call underlyingMockedVariableName variable %}
|
|
}
|
|
}
|
|
}
|
|
{% call accessLevel variable.readAccess %}nonisolated(unsafe) var {% call underlyingMockedVariableName variable %}: {{ variable.typeName }}{{ '!' if not variable.isOptional }}
|
|
{% if variable.throws %}
|
|
{% call variableThrowableErrorDeclaration variable %}
|
|
{% endif %}
|
|
{% call variableClosureDeclaration method %}
|
|
{% 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" %}
|
|
{% call accessLevel type.accessLevel %}nonisolated class {{ type.name | replace:"Protocol","" }}Mock: {{ type.name }}, @unchecked Sendable {
|
|
{% if type.accessLevel == "public" %}public init() {}{% endif %}
|
|
{% for variable in type.allVariables|!definedInExtension %}
|
|
{% if variable.isAsync or variable.throws %}{% call mockAsyncOrThrowingVariable variable %}{% elif variable.isOptional %}{% call mockOptionalVariable variable %}{% elif variable.isArray or variable.isDictionary %}{% call mockNonOptionalArrayOrDictionaryVariable variable %}{% else %}{% call mockNonOptionalVariable variable %}{% endif %}
|
|
{% endfor %}
|
|
{% if type.allMethods|static|count != 0 and type.allMethods|initializer|count != type.allMethods|static|count %}
|
|
static func reset()
|
|
{
|
|
{% for method in type.allMethods|static %}
|
|
{% call resetMethod method %}
|
|
{% endfor %}
|
|
}
|
|
{% endif %}
|
|
|
|
{% for method in type.allMethods|!definedInExtension %}
|
|
{% call mockMethod method %}
|
|
{% endfor %}
|
|
}
|
|
{% endif %}{% endfor %}
|
|
// swiftlint:enable all
|