Commit 14b092a9 authored by Thibault Wittemberg's avatar Thibault Wittemberg

project: add static code analysis

This commit:
- adds swiftlint analysis as custom build phase
- to install, see: https://github.com/realm/SwiftLint
- fix almost every error/warning messages detected by swiftlint

Change-Id: I0d15cecaa33c4f79dcd1417a2169f1e66fd2e551
parent 93d80295
disabled_rules: # rule identifiers to exclude from running
opt_in_rules: # some rules are only opt-in
- empty_count
excluded: # paths to ignore during linting. Takes precedence over `included`.
- Carthage
- Pods
force_cast: warning # implicitly
force_try:
severity: warning # explicitly
type_body_length:
- 300 # warning
- 400 # error
type_name:
min_length: 4 # only warning
max_length: # warning and error
warning: 40
error: 50
excluded: iPhone # excluded via string
identifier_name:
min_length: # only min_length
error: 3 # only error
excluded: # excluded via string array
- id
- URL
- GlobalAPIKey
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji)
function_body_length:
- 75
- 100
file_length:
warning: 600
error: 1200
line_length:
warning: 200
error: 250
......@@ -807,10 +807,11 @@
isa = PBXNativeTarget;
buildConfigurationList = 04399A201D1C2D9D00E99CD9 /* Build configuration list for PBXNativeTarget "Ring" */;
buildPhases = (
1ABE07C31F0C28E000D36361 /* ⚠️ Swiftlint Analysis */,
0273C3011E0C655900CF00BA /* ⚙️ Copy Frameworks */,
043999EF1D1C2D9D00E99CD9 /* Sources */,
043999F01D1C2D9D00E99CD9 /* Frameworks */,
043999F11D1C2D9D00E99CD9 /* Resources */,
0273C3011E0C655900CF00BA /* ShellScript */,
);
buildRules = (
);
......@@ -947,7 +948,7 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
0273C3011E0C655900CF00BA /* ShellScript */ = {
0273C3011E0C655900CF00BA /* ⚙️ Copy Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
......@@ -961,12 +962,27 @@
"$(SRCROOT)/Carthage/Build/iOS/RealmSwift.framework",
"$(SRCROOT)/Carthage/Build/iOS/RxRealm.framework",
);
name = "⚙️ Copy Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/usr/local/bin/carthage copy-frameworks";
};
1ABE07C31F0C28E000D36361 /* ⚠️ Swiftlint Analysis */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "⚠️ Swiftlint Analysis";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint > /dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
......
......@@ -28,30 +28,30 @@ import RealmSwift
- errors concerning the state of the accounts
*/
enum AccountState: String {
case Registered = "REGISTERED"
case Ready = "READY"
case Unregistered = "UNREGISTERED"
case Trying = "TRYING"
case Error = "ERROR"
case ErrorGeneric = "ERROR_GENERIC"
case ErrorAuth = "ERROR_AUTH"
case ErrorNetwork = "ERROR_NETWORK"
case ErrorHost = "ERROR_HOST"
case ErrorConfStun = "ERROR_CONF_STUN"
case ErrorExistStun = "ERROR_EXIST_STUN"
case ErrorServiceUnavailable = "ERROR_SERVICE_UNAVAILABLE"
case ErrorNotAcceptable = "ERROR_NOT_ACCEPTABLE"
case ErrorRequestTimeout = "Request Timeout"
case ErrorNeedMigration = "ERROR_NEED_MIGRATION"
case Initializing = "INITIALIZING"
case registered = "REGISTERED"
case ready = "READY"
case unregistered = "UNREGISTERED"
case trying = "TRYING"
case error = "ERROR"
case errorGeneric = "ERROR_GENERIC"
case errorAuth = "ERROR_AUTH"
case errorNetwork = "ERROR_NETWORK"
case errorHost = "ERROR_HOST"
case errorConfStun = "ERROR_CONF_STUN"
case errorExistStun = "ERROR_EXIST_STUN"
case errorServiceUnavailable = "ERROR_SERVICE_UNAVAILABLE"
case errorNotAcceptable = "ERROR_NOT_ACCEPTABLE"
case errorRequestTimeout = "Request Timeout"
case errorNeedMigration = "ERROR_NEED_MIGRATION"
case initializing = "INITIALIZING"
}
/**
The different types of account handled by Ring.
*/
enum AccountType: String {
case Ring = "RING"
case SIP = "SIP"
case ring = "RING"
case sip = "SIP"
}
/**
......@@ -63,11 +63,11 @@ enum AccountType: String {
- expose a clear interface to manipulate the configuration of an account
- keep this configuration
*/
class AccountConfigModel :Object {
class AccountConfigModel: Object {
/**
The collection of configuration elements.
*/
fileprivate var configValues = Dictionary<ConfigKeyModel, String>()
fileprivate var configValues = [ConfigKeyModel: String]()
/**
Constructor.
......@@ -76,7 +76,7 @@ class AccountConfigModel :Object {
- Parameter details: an optional collection of configuration elements
*/
convenience init(withDetails details: Dictionary<String, String>?) {
convenience init(withDetails details: [String: String]?) {
self.init()
if details != nil {
for (key, value) in details! {
......@@ -98,7 +98,7 @@ class AccountConfigModel :Object {
- Returns: a boolean indicating the value of the configuration element.
*/
func getBool(forConfigKeyModel configKeyModel : ConfigKeyModel) -> Bool {
func getBool(forConfigKeyModel configKeyModel: ConfigKeyModel) -> Bool {
return "true".caseInsensitiveCompare(self.get(withConfigKeyModel: configKeyModel))
== ComparisonResult.orderedSame
}
......@@ -111,8 +111,8 @@ class AccountConfigModel :Object {
- Returns: the value of the configuration element as a String. The result will be an empty
string in case of an issue.
*/
func get(withConfigKeyModel configKeyModel : ConfigKeyModel) -> String {
let value:String? = self.configValues[configKeyModel]
func get(withConfigKeyModel configKeyModel: ConfigKeyModel) -> String {
let value: String? = self.configValues[configKeyModel]
return value != nil ? value! : ""
}
}
......@@ -26,7 +26,7 @@ import RealmSwift
- NotEnoughData: some information are missing to create the object
*/
enum CredentialsError: Error {
case NotEnoughData
case notEnoughData
}
/**
......@@ -35,7 +35,7 @@ enum CredentialsError: Error {
Its responsability:
- keep the credentials of an account.
*/
class AccountCredentialsModel :Object {
class AccountCredentialsModel: Object {
dynamic var username: String = ""
dynamic var password: String = ""
dynamic var accountRealm: String = ""
......@@ -63,14 +63,14 @@ class AccountCredentialsModel :Object {
- Throws: CredentialsError
*/
convenience init(withRawaData raw: Dictionary<String, String>) throws {
convenience init(withRawaData raw: [String: String]) throws {
self.init()
let username = raw[ConfigKey.AccountUsername.rawValue]
let password = raw[ConfigKey.AccountPassword.rawValue]
let accountRealm = raw[ConfigKey.AccountRealm.rawValue]
let username = raw[ConfigKey.accountUsername.rawValue]
let password = raw[ConfigKey.accountPassword.rawValue]
let accountRealm = raw[ConfigKey.accountRealm.rawValue]
if username == nil || password == nil || accountRealm == nil {
throw CredentialsError.NotEnoughData
throw CredentialsError.notEnoughData
}
self.username = username!
......
......@@ -26,13 +26,13 @@ import Foundation
Errors that can be thrown when trying to build an AccountModel
*/
enum AccountModelError: Error {
case UnexpectedError
case unexpectedError
}
/**
A class representing an account.
*/
class AccountModel : Object {
class AccountModel: Object {
// MARK: Public members
dynamic var id: String = ""
dynamic var registeringUsername = false
......@@ -48,10 +48,10 @@ class AccountModel : Object {
}
convenience init(withAccountId accountId: String,
details: AccountConfigModel,
volatileDetails: AccountConfigModel,
credentials: List<AccountCredentialsModel>,
devices: [DeviceModel]) throws {
details: AccountConfigModel,
volatileDetails: AccountConfigModel,
credentials: List<AccountCredentialsModel>,
devices: [DeviceModel]) throws {
self.init()
self.id = accountId
self.details = details
......@@ -59,7 +59,7 @@ class AccountModel : Object {
self.devices.append(objectsIn: devices)
}
public static func ==(lhs: AccountModel, rhs: AccountModel) -> Bool {
public static func == (lhs: AccountModel, rhs: AccountModel) -> Bool {
return lhs.id == rhs.id
}
......
......@@ -39,9 +39,9 @@ struct AccountModelHelper {
- Returns: true if the account is considered as a SIP account
*/
func isAccountSip() -> Bool {
let sipString = AccountType.SIP.rawValue
let sipString = AccountType.sip.rawValue
let accountType = self.account.details?
.get(withConfigKeyModel: ConfigKeyModel.init(withKey: .AccountType))
.get(withConfigKeyModel: ConfigKeyModel.init(withKey: .accountType))
return sipString.compare(accountType!) == ComparisonResult.orderedSame
}
......@@ -51,9 +51,9 @@ struct AccountModelHelper {
- Returns: true if the account is considered as a Ring account
*/
func isAccountRing() -> Bool {
let ringString = AccountType.Ring.rawValue
let ringString = AccountType.ring.rawValue
let accountType = self.account.details?
.get(withConfigKeyModel: ConfigKeyModel.init(withKey: .AccountType))
.get(withConfigKeyModel: ConfigKeyModel.init(withKey: .accountType))
return ringString.compare(accountType!) == ComparisonResult.orderedSame
}
......@@ -64,7 +64,7 @@ struct AccountModelHelper {
*/
func isEnabled() -> Bool {
return (self.account.details!
.getBool(forConfigKeyModel: ConfigKeyModel.init(withKey: .AccountEnable)))
.getBool(forConfigKeyModel: ConfigKeyModel.init(withKey: .accountEnable)))
}
/**
......@@ -74,7 +74,7 @@ struct AccountModelHelper {
*/
func getRegistrationState() -> String {
return (self.account.volatileDetails!
.get(withConfigKeyModel: ConfigKeyModel.init(withKey: .AccountRegistrationStatus)))
.get(withConfigKeyModel: ConfigKeyModel.init(withKey: .accountRegistrationStatus)))
}
/**
......@@ -84,16 +84,16 @@ struct AccountModelHelper {
*/
func isInError() -> Bool {
let state = self.getRegistrationState()
return (state.compare(AccountState.Error.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.ErrorAuth.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.ErrorConfStun.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.ErrorExistStun.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.ErrorGeneric.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.ErrorHost.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.ErrorNetwork.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.ErrorNotAcceptable.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.ErrorServiceUnavailable.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.ErrorRequestTimeout.rawValue) == ComparisonResult.orderedSame)
return (state.compare(AccountState.error.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.errorAuth.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.errorConfStun.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.errorExistStun.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.errorGeneric.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.errorHost.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.errorNetwork.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.errorNotAcceptable.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.errorServiceUnavailable.rawValue) == ComparisonResult.orderedSame) ||
(state.compare(AccountState.errorRequestTimeout.rawValue) == ComparisonResult.orderedSame)
}
/**
......@@ -102,18 +102,16 @@ struct AccountModelHelper {
- Parameter: a list of credentials to apply to the account. A nil parameter will clear the
credentials of the account.
*/
mutating func setCredentials(_ credentials: Array<Dictionary<String, String>>?) -> AccountModel {
mutating func setCredentials(_ credentials: [[String: String]]?) -> AccountModel {
self.account.credentialDetails.removeAll()
if credentials != nil {
for (credential) in credentials! {
do {
let accountCredentialModel = try AccountCredentialsModel(withRawaData: credential)
self.account.credentialDetails.append(accountCredentialModel)
}
catch CredentialsError.NotEnoughData {
} catch CredentialsError.notEnoughData {
print("Not enough data to create a credential")
}
catch {
} catch {
print("Unexpected error")
}
}
......@@ -121,9 +119,9 @@ struct AccountModelHelper {
return self.account
}
var ringId :String? {
var ringId: String? {
let accountUsernameKey = ConfigKeyModel(withKey: ConfigKey.AccountUsername)
let accountUsernameKey = ConfigKeyModel(withKey: ConfigKey.accountUsername)
let accountUsername = self.account.details?.get(withConfigKeyModel: accountUsernameKey)
let ringIdPrefix = "ring:"
......
......@@ -22,81 +22,81 @@
The different configuration keys handled by Ring.
*/
enum ConfigKey: String {
case Mailbox = "Account.mailbox"
case RegistrationExpire = "Account.registrationExpire"
case CredentialNumber = "Credential.count"
case AccountDTMFType = "Account.dtmfType"
case RingtonePath = "Account.ringtonePath"
case RingtoneEnabled = "Account.ringtoneEnabled"
case KeepAliveEnabled = "Account.keepAliveEnabled"
case LocalInterface = "Account.localInterface"
case PublishedSameAsLocal = "Account.publishedSameAsLocal"
case LocalPort = "Account.localPort"
case PublishedPort = "Account.publishedPort"
case PublishedAddress = "Account.publishedAddress"
case StunServer = "STUN.server"
case StunEnable = "STUN.enable"
case TurnServer = "TURN.server"
case TurnEnable = "TURN.enable"
case TurnUsername = "TURN.username"
case TurnPassword = "TURN.password"
case TurnRealm = "TURN.realm"
case AudioPortMin = "Account.audioPortMin"
case AudioPortMax = "Account.audioPortMax"
case AccountUserAgent = "Account.useragent"
case AccountUpnpEnabled = "Account.upnpEnabled"
case AccountRouteSet = "Account.routeset"
case AccountAutoAnswer = "Account.autoAnswer"
case AccountAlias = "Account.alias"
case AccountHostname = "Account.hostname"
case AccountUsername = "Account.username"
case AccountPassword = "Account.password"
case AccountRealm = "Account.realm"
case AccountType = "Account.type"
case AccountEnable = "Account.enable"
case AccountActive = "Account.active"
case AccountDeviceId = "Account.deviceID"
case VideoEnabled = "Account.videoEnabled"
case VideoPortMin = "Account.videoPortMin"
case VideoPortMax = "Account.videoPortMax"
case PresenceEnabled = "Account.presenceEnabled"
case ArchivePassword = "Account.archivePassword"
case ArchivePIN = "Account.archivePIN"
case DisplayName = "Account.displayName"
case EthAccount = "ETH.account"
case TLSListenerPort = "TLS.listenerPort"
case TLSEnable = "TLS.enable"
case TLSCaListFile = "TLS.certificateListFile"
case TLSPrivateKeyFile = "TLS.privateKeyFile"
case TLSPassword = "TLS.password"
case TLSMethod = "TLS.method"
case TLSCiphers = "TLS.ciphers"
case TLSServerName = "TLS.serverName"
case TLSVerifyServer = "TLS.verifyServer"
case TLSVerifyClient = "TLS.verifyClient"
case TLSRequireClientCertificate = "TLS.requireClientCertificate"
case TLSNegociationTimeoutSec = "TLS.negotiationTimeoutSec"
case AccountRegisteredName = "Account.registredName"
case AccountRegistrationStatus = "Account.registrationStatus"
case AccountRegistrationStateCode = "Account.registrationCode"
case AccountRegistrationStateDesc = "Account.registrationDescription"
case SRTPEnable = "SRTP.enable"
case SRTPKeyExchange = "SRTP.keyExchange"
case SRTPEncryptionAlgo = "SRTP.encryptionAlgorithm"
case SRTPRTPFallback = "SRTP.rtpFallback"
case RingNsAccount = "RingNS.account"
case RingNsHost = "RingNS.host"
case DHTPort = "DHT.port"
case DHTPublicIn = "DHT.PublicInCalls"
case AccountAllowCertFromHistory = "Account.allowCertFromHistory"
case AccountAllowCertFromTrusted = "Account.allowCertFromTrusted"
case AccountAllowCertFromContact = "Account.allowCertFromContact"
case AccountHasCustomUserAgent = "Account.hasCustomUserAgent"
case AccountActiveCallLimit = "Account.activeCallLimit"
case TLSCertificateFile = "TLS.certificateFile"
case RingNsURI = "RingNS.uri"
case AccountPresenceSubscribeSupported = "Account.presenceSubscribeSupported"
case AccountDeviceName = "Account.deviceName"
case mailbox = "Account.mailbox"
case registrationExpire = "Account.registrationExpire"
case credentialNumber = "Credential.count"
case accountDTMFType = "Account.dtmfType"
case ringtonePath = "Account.ringtonePath"
case ringtoneEnabled = "Account.ringtoneEnabled"
case keepAliveEnabled = "Account.keepAliveEnabled"
case localInterface = "Account.localInterface"
case publishedSameAsLocal = "Account.publishedSameAsLocal"
case localPort = "Account.localPort"
case publishedPort = "Account.publishedPort"
case publishedAddress = "Account.publishedAddress"
case stunServer = "STUN.server"
case stunEnable = "STUN.enable"
case turnServer = "TURN.server"
case turnEnable = "TURN.enable"
case turnUsername = "TURN.username"
case turnPassword = "TURN.password"
case turnRealm = "TURN.realm"
case audioPortMin = "Account.audioPortMin"
case audioPortMax = "Account.audioPortMax"
case accountUserAgent = "Account.useragent"
case accountUpnpEnabled = "Account.upnpEnabled"
case accountRouteSet = "Account.routeset"
case accountAutoAnswer = "Account.autoAnswer"
case accountAlias = "Account.alias"
case accountHostname = "Account.hostname"
case accountUsername = "Account.username"
case accountPassword = "Account.password"
case accountRealm = "Account.realm"
case accountType = "Account.type"
case accountEnable = "Account.enable"
case accountActive = "Account.active"
case accountDeviceId = "Account.deviceID"
case videoEnabled = "Account.videoEnabled"
case videoPortMin = "Account.videoPortMin"
case videoPortMax = "Account.videoPortMax"
case presenceEnabled = "Account.presenceEnabled"
case archivePassword = "Account.archivePassword"
case archivePIN = "Account.archivePIN"
case displayName = "Account.displayName"
case ethAccount = "ETH.account"
case tlsListenerPort = "TLS.listenerPort"
case tlsEnable = "TLS.enable"
case tlsCaListFile = "TLS.certificateListFile"
case tlsPrivateKeyFile = "TLS.privateKeyFile"
case tlsPassword = "TLS.password"
case tlsMethod = "TLS.method"
case tlsCiphers = "TLS.ciphers"
case tlsServerName = "TLS.serverName"
case tlsVerifyServer = "TLS.verifyServer"
case tlsVerifyClient = "TLS.verifyClient"
case tlsRequireClientCertificate = "TLS.requireClientCertificate"
case tlsNegociationTimeoutSec = "TLS.negotiationTimeoutSec"
case accountRegisteredName = "Account.registredName"
case accountRegistrationStatus = "Account.registrationStatus"
case accountRegistrationStateCode = "Account.registrationCode"
case accountRegistrationStateDesc = "Account.registrationDescription"
case srtpEnable = "SRTP.enable"
case srtpKeyExchange = "SRTP.keyExchange"
case srtpEncryptionAlgo = "SRTP.encryptionAlgorithm"
case srtpRTPFallback = "SRTP.rtpFallback"
case ringNsAccount = "RingNS.account"
case ringNsHost = "RingNS.host"
case dhtPort = "DHT.port"
case dhtPublicIn = "DHT.PublicInCalls"
case accountAllowCertFromHistory = "Account.allowCertFromHistory"
case accountAllowCertFromTrusted = "Account.allowCertFromTrusted"
case accountAllowCertFromContact = "Account.allowCertFromContact"
case accountHasCustomUserAgent = "Account.hasCustomUserAgent"
case accountActiveCallLimit = "Account.activeCallLimit"
case tlsCertificateFile = "TLS.certificateFile"
case ringNsURI = "RingNS.uri"
case accountPresenceSubscribeSupported = "Account.presenceSubscribeSupported"
case accountDeviceName = "Account.deviceName"
}
/**
......@@ -111,15 +111,15 @@ struct ConfigKeyModel: Hashable {
/**
List of all the ConfigKeys that are considered as TwoStates configurations.
*/
let twoStates: Array<ConfigKey> = [.AccountEnable,
.VideoEnabled,
.RingtoneEnabled,
.KeepAliveEnabled,
.PublishedSameAsLocal,
.StunEnable,
.TurnEnable,
.AccountAutoAnswer,
.AccountUpnpEnabled]
let twoStates: [ConfigKey] = [.accountEnable,
.videoEnabled,
.ringtoneEnabled,
.keepAliveEnabled,
.publishedSameAsLocal,
.stunEnable,
.turnEnable,
.accountAutoAnswer,
.accountUpnpEnabled]
/**
Constructor.
......
......@@ -53,29 +53,29 @@ class CreateRingAccountViewModel {
*/
fileprivate var nameService: NameService
//MARK: - Rx Variables and Observers
// MARK: - Rx Variables and Observers
var username = Variable<String>("")
var password = Variable<String>("")
var repeatPassword = Variable<String>("")
var passwordValid :Observable<Bool>!
var passwordsEqual :Observable<Bool>!
var canCreateAccount :Observable<Bool>!
var passwordValid: Observable<Bool>!
var passwordsEqual: Observable<Bool>!
var canCreateAccount: Observable<Bool>!
var registerUsername = Variable<Bool>(true)
var hasNewPassword :Observable<Bool>!
var hidePasswordError :Observable<Bool>!
var hideRepeatPasswordError :Observable<Bool>!
var hasNewPassword: Observable<Bool>!
var hidePasswordError: Observable<Bool>!
var hideRepeatPasswordError: Observable<Bool>!
var accountCreationState = PublishSubject<AccountCreationState>()
/**
Message presented to the user in function of the status of the current username lookup request
*/
var usernameValidationMessage :Observable<String>!
var usernameValidationMessage: Observable<String>!
//MARK: -
// MARK: -
/**
Default constructor
......@@ -121,15 +121,14 @@ class CreateRingAccountViewModel {