Slather logo

Coverage for "RoutingError.swift" : 98.18%

(54 of 55 relevant lines covered)

RouteComposer/Classes/RoutingError.swift

1
//
2
// RouteComposer
3
// RoutingError.swift
4
// https://github.com/ekazaev/route-composer
5
//
6
// Created by Eugene Kazaev in 2018-2022.
7
// Distributed under the MIT license.
8
//
9
// Become a sponsor:
10
// https://github.com/sponsors/ekazaev
11
//
12
13
import Foundation
14
15
/// Routing `Error` representation
16
public enum RoutingError: Error, CustomStringConvertible {
17
18
    // MARK: Internal entities
19
20
    /// Describes an error happened to the initial view controller
21
    public enum InitialControllerErrorState: CustomStringConvertible {
22
23
        /// View controller not found
24
        case notFound
25
26
        /// View controller deallocated
27
        case deallocated
28
29
        public var description: String {
5x
30
            switch self {
5x
31
            case .deallocated:
5x
32
                return "Initial controller deallocated"
2x
33
            case .notFound:
5x
34
                return "Initial controller not found"
3x
35
            }
5x
36
        }
5x
37
38
    }
39
40
    /// Error context holder
41
    public struct Context: CustomStringConvertible {
42
43
        /// Message describing error that happened
44
        public let debugDescription: String
45
46
        /// Underlying error if present
47
        public let underlyingError: Error?
48
49
        /// Constructor
50
        public init(_ debugDescription: String, underlyingError: Error? = nil) {
212x
51
            self.debugDescription = debugDescription
212x
52
            self.underlyingError = underlyingError
212x
53
        }
212x
54
55
        public var description: String {
82x
56
            let errorDescription: String?
82x
57
            if let underlyingError {
82x
58
                errorDescription = "\(underlyingError)"
13x
59
            } else {
82x
60
                errorDescription = nil
69x
61
            }
82x
62
            let descriptionParts = [!debugDescription.isEmpty ? debugDescription : nil, errorDescription].compactMap { $0 }
164x
63
            guard descriptionParts.isEmpty else {
82x
64
                return descriptionParts.joined(separator: " -> ")
81x
65
            }
81x
66
1x
67
            return "No valuable information provided"
1x
68
        }
82x
69
70
    }
71
72
    // MARK: Error types
73
74
    /// Type mismatch error
75
    case typeMismatch(type: Any.Type, expectedType: Any.Type, RoutingError.Context)
76
77
    /// The view controllers stack integration failed
78
    case compositionFailed(RoutingError.Context)
79
80
    /// The view controller can not be dismissed. See `RoutingInterceptable.canBeDismissed`.
81
    case cantBeDismissed(RoutingError.Context)
82
83
    /// Initial view controller error
84
    case initialController(InitialControllerErrorState, RoutingError.Context)
85
86
    /// Message describing error that happened
87
    case generic(RoutingError.Context)
88
89
    // MARK: Helper methods
90
91
    public var description: String {
67x
92
        switch self {
67x
93
        case let .typeMismatch(type, expectedType, context):
67x
94
            return "Type Mismatch Error: Type \(String(describing: type)) is not equal to the expected type \(String(describing: expectedType)). " +
17x
95
                "\(context.description)"
17x
96
        case let .compositionFailed(context):
67x
97
            return "Composition Failed Error: \(context.description)"
16x
98
        case let .initialController(state, context):
67x
99
            return "Initial Controller Error: \(state). \(context.description)"
5x
100
        case let .cantBeDismissed(context):
67x
101
            return "View Controller Can Not Be Dismissed Error: \(context.description)"
8x
102
        case let .generic(context):
67x
103
            return "Generic Error: \(context.description)"
21x
104
        }
67x
105
    }
67x
106
107
    /// Returns `RoutingError.Context` instance
108
    public var context: RoutingError.Context {
5x
109
        switch self {
5x
110
        case let .typeMismatch(_, _, context):
5x
111
            return context
1x
112
        case let .compositionFailed(context):
5x
113
            return context
1x
114
        case let .initialController(_, context):
5x
115
            return context
1x
116
        case let .cantBeDismissed(context):
5x
117
            return context
!
118
        case let .generic(context):
5x
119
            return context
2x
120
        }
5x
121
    }
5x
122
123
}