1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
//
// RoutingTests.swift
// MullvadVPNTests
//
// Created by pronebird on 14/08/2023.
// Copyright © 2025 Mullvad VPN AB. All rights reserved.
//
import XCTest
@testable import Routing
@MainActor
final class RoutingTests: XCTestCase {
private func createDelegate<T: AppRouteProtocol>(shouldPresent: Bool = true) -> RouterBlockDelegate<T> {
let delegate = RouterBlockDelegate<T>()
delegate.handleRoute = { _, _, completion in completion(Coordinator()) }
delegate.shouldPresent = { _ in shouldPresent }
return delegate
}
// MARK: Horizontal flow tests
func testPresentHorizontalRoute() throws {
enum TestRoute: AppRouteProtocol {
case one
var isExclusive: Bool { false }
var supportsSubNavigation: Bool { false }
var routeGroup: TestRouteGroup { .horizontal }
}
let delegate: RouterBlockDelegate<TestRoute> = createDelegate()
let router = ApplicationRouter<TestRoute>(delegate)
router.present(.one)
XCTAssertTrue(router.isPresenting(route: .one))
}
func testShouldDropHorizontalRoute() throws {
enum TestRoute: AppRouteProtocol {
case one
var isExclusive: Bool { false }
var supportsSubNavigation: Bool { false }
var routeGroup: TestRouteGroup { .horizontal }
}
let delegate: RouterBlockDelegate<TestRoute> = createDelegate(shouldPresent: false)
let router = ApplicationRouter<TestRoute>(delegate)
router.present(.one)
XCTAssertFalse(router.isPresenting(route: .one))
}
func testShouldDropIdenticalHorizontalRouteInSequence() throws {
enum TestRoute: AppRouteProtocol {
case one
var isExclusive: Bool { false }
var supportsSubNavigation: Bool { false }
var routeGroup: TestRouteGroup { .horizontal }
}
let delegate: RouterBlockDelegate<TestRoute> = createDelegate()
let router = ApplicationRouter<TestRoute>(delegate)
router.present(.one)
router.present(.one)
XCTAssertEqual(router.presentedRoutes[.horizontal]?.count, 1)
}
// MARK: Modal flow tests
func testPresentModalRoutesOfDifferentLevels() throws {
enum TestRoute: AppRouteProtocol {
case one, two
var isExclusive: Bool { false }
var supportsSubNavigation: Bool { false }
var routeGroup: TestRouteGroup { self == .one ? .modalOne : .modalTwo }
}
let delegate: RouterBlockDelegate<TestRoute> = createDelegate()
let router = ApplicationRouter<TestRoute>(delegate)
router.present(.one)
router.present(.two)
XCTAssertEqual(router.modalStack.count, 2)
}
func testPresentModalRoutesOfDifferentLevelsInWrongOrder() throws {
enum TestRoute: AppRouteProtocol {
case one, two
var isExclusive: Bool { false }
var supportsSubNavigation: Bool { false }
var routeGroup: TestRouteGroup { self == .one ? .modalOne : .modalTwo }
}
let delegate: RouterBlockDelegate<TestRoute> = createDelegate()
let router = ApplicationRouter<TestRoute>(delegate)
router.present(.two)
router.present(.one)
XCTAssertTrue(router.isPresenting(route: .two))
XCTAssertEqual(router.modalStack.count, 1)
}
func testShouldDropSameLevelModalRouteIfPreceededByExclusive() throws {
enum TestRoute: AppRouteProtocol {
case one, two
var isExclusive: Bool { self == .one }
var supportsSubNavigation: Bool { false }
var routeGroup: TestRouteGroup { .modalOne }
}
let delegate: RouterBlockDelegate<TestRoute> = createDelegate()
let router = ApplicationRouter<TestRoute>(delegate)
router.present(.one)
router.present(.two)
XCTAssertTrue(router.isPresenting(route: .one))
XCTAssertEqual(router.modalStack.count, 1)
}
}
enum TestRouteGroup: AppRouteGroupProtocol {
case horizontal, modalOne, modalTwo
var isModal: Bool {
switch self {
case .horizontal:
return false
case .modalOne, .modalTwo:
return true
}
}
var modalLevel: Int {
switch self {
case .horizontal:
return 0
case .modalOne:
return 1
case .modalTwo:
return 2
}
}
}
|