Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Commit 2274be2

Browse files
committed
add tests
1 parent 9a90250 commit 2274be2

File tree

3 files changed

+252
-79
lines changed

3 files changed

+252
-79
lines changed

DuckDuckGo-iOS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

DuckDuckGo/NetworkProtectionDNSSettingsViewModel.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ final class NetworkProtectionDNSSettingsViewModel: ObservableObject {
3131

3232
@Published public var dnsSettings: NetworkProtectionDNSSettings
3333

34-
@Published public var isCustomDNSSelected = false
34+
@Published public var isCustomDNSSelected: Bool
3535

3636
@Published var isBlockRiskyDomainsOn: Bool {
3737
didSet {
3838
applyDNSSettings()
3939
}
4040
}
4141

42-
@Published public var customDNSServers = ""
42+
@Published public var customDNSServers: String
4343

4444
@Published public var isApplyButtonEnabled = false
4545

Lines changed: 243 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,249 @@
1-
////
2-
//// NetworkProtectionDNSSettingsViewModelTests.swift
3-
//// DuckDuckGo
4-
////
5-
//// Copyright © 2025 DuckDuckGo. All rights reserved.
6-
////
7-
//// Licensed under the Apache License, Version 2.0 (the "License");
8-
//// you may not use this file except in compliance with the License.
9-
//// You may obtain a copy of the License at
10-
////
11-
//// http://www.apache.org/licenses/LICENSE-2.0
12-
////
13-
//// Unless required by applicable law or agreed to in writing, software
14-
//// distributed under the License is distributed on an "AS IS" BASIS,
15-
//// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16-
//// See the License for the specific language governing permissions and
17-
//// limitations under the License.
18-
////
191
//
20-
//import XCTest
21-
//import NetworkProtection
22-
//@testable import DuckDuckGo
2+
// NetworkProtectionDNSSettingsViewModelTests.swift
3+
// DuckDuckGo
234
//
24-
//final class NetworkProtectionDNSSettingsViewModelTests: XCTestCase {
5+
// Copyright © 2025 DuckDuckGo. All rights reserved.
256
//
26-
// var model: NetworkProtectionDNSSettingsViewModel!
27-
// let userDefaults = UserDefaults(suiteName: "TestDefaults")!
28-
// var vpnSettings: VPNSettings!
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
2910
//
30-
// override func setUpWithError() throws {
31-
// vpnSettings = VPNSettings(defaults: userDefaults)
32-
// model = NetworkProtectionDNSSettingsViewModel(settings: vpnSettings, controller: MockTunnelController(), featureFlagger: MockFeatureFlagger())
33-
// }
11+
// http://www.apache.org/licenses/LICENSE-2.0
3412
//
35-
// override func tearDownWithError() throws {
36-
// userDefaults.removePersistentDomain(forName: "TestDefaults")
37-
// vpnSettings = nil
38-
// model = nil
39-
// }
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an "AS IS" BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
4018
//
41-
// func testInitialState() {
42-
// XCTAssertEqual(model.dnsSettings, vpnSettings.dnsSettings)
43-
// XCTAssertFalse(model.isCustomDNSSelected)
44-
// XCTAssertEqual(model.customDNSServers, vpnSettings.customDnsServers.joined(separator: ", "))
45-
// XCTAssertTrue(model.isBlockRiskyDomainsOn)
46-
// }
47-
//
48-
// func test_WhenUpdateDNSSettingsToCustomThenPropagatesToVpnSettings() {
49-
// // WHEN
50-
// model.isCustomDNSSelected = true
51-
// model.customDNSServers = "1.1.1.1, 8.8.8.8"
52-
//
53-
// // THEN
54-
// switch vpnSettings.dnsSettings {
55-
// case .custom(let servers):
56-
// XCTAssertEqual(servers, ["1.1.1.1", "8.8.8.8"], "Custom DNS servers should be updated correctly.")
57-
// default:
58-
// XCTFail("Expected dnsSettings to be .custom, but got \(vpnSettings.dnsSettings)")
59-
// }
60-
// }
61-
//
62-
//
63-
//}
64-
//
65-
//final class MockTunnelController: TunnelController {
66-
// func start() async {
67-
// }
68-
//
69-
// func stop() async {
70-
// }
71-
//
72-
// func command(_ command: NetworkProtection.VPNCommand) async throws {
73-
// }
74-
//
75-
// var isConnected: Bool = false
76-
//}
19+
20+
import XCTest
21+
import NetworkProtection
22+
@testable import DuckDuckGo
23+
24+
final class NetworkProtectionDNSSettingsViewModelTests: XCTestCase {
25+
26+
var model: NetworkProtectionDNSSettingsViewModel!
27+
let userDefaults = UserDefaults(suiteName: "TestDefaults")!
28+
var vpnSettings: VPNSettings!
29+
30+
override func setUpWithError() throws {
31+
vpnSettings = VPNSettings(defaults: userDefaults)
32+
model = NetworkProtectionDNSSettingsViewModel(settings: vpnSettings, controller: MockTunnelController(), featureFlagger: MockFeatureFlagger())
33+
}
34+
35+
override func tearDownWithError() throws {
36+
userDefaults.removePersistentDomain(forName: "TestDefaults")
37+
vpnSettings = nil
38+
model = nil
39+
}
40+
41+
func testInitialState() {
42+
XCTAssertEqual(model.dnsSettings, vpnSettings.dnsSettings)
43+
XCTAssertFalse(model.isCustomDNSSelected)
44+
XCTAssertEqual(model.customDNSServers, vpnSettings.customDnsServers.joined(separator: ", "))
45+
XCTAssertTrue(model.isBlockRiskyDomainsOn)
46+
}
47+
48+
func test_WhenUpdateDNSSettingsToCustomThenPropagatesToVpnSettings() {
49+
// GIVEN
50+
model.customDNSServers = "1.1.1.1"
51+
model.isCustomDNSSelected = true
52+
53+
// WHEN
54+
model.applyDNSSettings()
55+
56+
// THEN
57+
switch vpnSettings.dnsSettings {
58+
case .custom(let servers):
59+
XCTAssertEqual(servers, ["1.1.1.1"], "Custom DNS servers should be updated correctly.")
60+
default:
61+
XCTFail("Expected dnsSettings to be .custom, but got \(vpnSettings.dnsSettings)")
62+
}
63+
}
64+
65+
func test_WhenUpdateDNSSettingsToDefaultWithThenPropagatesToVpnSettings() {
66+
// GIVEN
67+
model.isCustomDNSSelected = false
68+
model.isBlockRiskyDomainsOn = true
69+
70+
// WHEN
71+
model.applyDNSSettings()
72+
73+
// THEN
74+
switch vpnSettings.dnsSettings {
75+
case .ddg(let blockRiskyDomains):
76+
XCTAssertTrue(blockRiskyDomains, "Expected blockRiskyDomains to be false.")
77+
default:
78+
XCTFail("Expected dnsSettings to be .ddg, but got \(vpnSettings.dnsSettings)")
79+
}
80+
}
81+
82+
func test_WhenUpdateDNSSettingsToDefaultWithBlockOffThenPropagatesToVpnSettings() {
83+
// GIVEN
84+
model.isCustomDNSSelected = false
85+
model.isBlockRiskyDomainsOn = false
86+
87+
// WHEN
88+
model.applyDNSSettings()
89+
90+
// THEN
91+
switch vpnSettings.dnsSettings {
92+
case .ddg(let blockRiskyDomains):
93+
XCTAssertFalse(blockRiskyDomains, "Expected blockRiskyDomains to be false.")
94+
default:
95+
XCTFail("Expected dnsSettings to be .ddg, but got \(vpnSettings.dnsSettings)")
96+
}
97+
}
98+
99+
func test_WhenMovingFromDefaultToCustomAndBackToDefaultThenBlockSettingRetainedToFalse() {
100+
// GIVEN
101+
model.isCustomDNSSelected = false
102+
model.isBlockRiskyDomainsOn = false
103+
model.applyDNSSettings()
104+
model.isCustomDNSSelected = true
105+
model.customDNSServers = "1.1.1.1"
106+
model.applyDNSSettings()
107+
108+
// WHEN
109+
model.isCustomDNSSelected = false
110+
model.applyDNSSettings()
111+
112+
// THEN
113+
switch vpnSettings.dnsSettings {
114+
case .ddg(let blockRiskyDomains):
115+
XCTAssertFalse(blockRiskyDomains, "Expected blockRiskyDomains to be false.")
116+
default:
117+
XCTFail("Expected dnsSettings to be .ddg, but got \(vpnSettings.dnsSettings)")
118+
}
119+
}
120+
121+
func test_WhenMovingFromDefaultToCustomAndBackToDefaultThenBlockSettingRetainedToTrue() {
122+
// GIVEN
123+
model.isCustomDNSSelected = false
124+
model.isBlockRiskyDomainsOn = true
125+
model.applyDNSSettings()
126+
model.isCustomDNSSelected = true
127+
model.customDNSServers = "1.1.1.1"
128+
model.applyDNSSettings()
129+
130+
// WHEN
131+
model.isCustomDNSSelected = false
132+
model.applyDNSSettings()
133+
134+
// THEN
135+
switch vpnSettings.dnsSettings {
136+
case .ddg(let blockRiskyDomains):
137+
XCTAssertTrue(blockRiskyDomains, "Expected blockRiskyDomains to be true.")
138+
default:
139+
XCTFail("Expected dnsSettings to be .ddg, but got \(vpnSettings.dnsSettings)")
140+
}
141+
}
142+
143+
func test_WhenMovingFromCustomToDefaultAndBackToCustomThenPreviouslySelectedServerRetained() {
144+
// GIVEN
145+
model.isCustomDNSSelected = true
146+
model.customDNSServers = "1.1.1.1"
147+
model.applyDNSSettings()
148+
model.isCustomDNSSelected = false
149+
model.applyDNSSettings()
150+
151+
// WHEN
152+
model.isCustomDNSSelected = true
153+
model.applyDNSSettings()
154+
155+
// THEN
156+
switch vpnSettings.dnsSettings {
157+
case .custom(let servers):
158+
XCTAssertEqual(servers, ["1.1.1.1"], "Custom DNS servers should be updated correctly.")
159+
default:
160+
XCTFail("Expected dnsSettings to be .custom, but got \(vpnSettings.dnsSettings)")
161+
}
162+
}
163+
164+
func testWhenUpdateDNSSettingsToCustomAndNoServerProvidedPreviousDnsSettingApplies() {
165+
// GIVEN
166+
model.isCustomDNSSelected = false
167+
model.applyDNSSettings()
168+
let previousDNS = vpnSettings.dnsSettings
169+
170+
// WHEN
171+
model.customDNSServers = ""
172+
model.isCustomDNSSelected = true
173+
model.applyDNSSettings()
174+
175+
// THEN
176+
XCTAssertEqual(vpnSettings.dnsSettings, previousDNS, "DNS settings should remain unchanged when no custom DNS is provided.")
177+
}
178+
179+
func testToggleDNSSettings() {
180+
// GIVEN
181+
let initial = model.isCustomDNSSelected
182+
183+
// WHEN
184+
model.toggleDNSSettings()
185+
186+
// THEN
187+
XCTAssertEqual(model.isCustomDNSSelected, !initial, "toggleDNSSettings should invert the value.")
188+
}
189+
190+
func testToggleIsBlockRiskyDomainsOn() {
191+
// GIVEN
192+
let initial = model.isBlockRiskyDomainsOn
193+
194+
// WHEN
195+
model.toggleIsBlockRiskyDomainsOn()
196+
197+
// THEN
198+
XCTAssertEqual(model.isBlockRiskyDomainsOn, !initial, "toggleIsBlockRiskyDomainsOn should invert the value.")
199+
}
200+
201+
func testUpdateApplyButtonStateWhenValid() {
202+
// GIVEN
203+
model.isCustomDNSSelected = true
204+
model.customDNSServers = "1.1.1.1"
205+
206+
// WHEN
207+
model.updateApplyButtonState()
208+
209+
// THEN
210+
XCTAssertTrue(model.isApplyButtonEnabled, "Apply button should be enabled for valid custom DNS.")
211+
}
212+
213+
func testUpdateApplyButtonStateWhenInvalid() {
214+
// GIVEN
215+
model.isCustomDNSSelected = true
216+
model.customDNSServers = "invalid"
217+
218+
// WHEN
219+
model.updateApplyButtonState()
220+
221+
// THEN
222+
XCTAssertFalse(model.isApplyButtonEnabled, "Apply button should be disabled for invalid custom DNS.")
223+
}
224+
225+
func testUpdateApplyButtonStateWhenDefault() {
226+
// GIVEN
227+
model.isCustomDNSSelected = false
228+
229+
// WHEN
230+
model.updateApplyButtonState()
231+
232+
// THEN
233+
XCTAssertTrue(model.isApplyButtonEnabled, "Apply button should be enabled in default mode.")
234+
}
235+
236+
}
237+
238+
private final class MockTunnelController: TunnelController {
239+
func start() async {
240+
}
241+
242+
func stop() async {
243+
}
244+
245+
func command(_ command: NetworkProtection.VPNCommand) async throws {
246+
}
247+
248+
var isConnected: Bool = false
249+
}

0 commit comments

Comments
 (0)