Skip to content

Commit f9eb85e

Browse files
committed
Expand unit tests to cover config, posture, and MFA models
1 parent 15baca0 commit f9eb85e

File tree

8 files changed

+549
-0
lines changed

8 files changed

+549
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
xcuserdata/
22
DerivedData/
3+
.derived-data-log-*
34
dist/
45
include/
56
build/

CZiti.xcodeproj/project.pbxproj

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
1173FC5AE4A751591E38F2B4 /* ZitiInterceptConfigV1Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D2CE058E93C639D85230E5A /* ZitiInterceptConfigV1Tests.swift */; };
1011
14CC88CB4E471239322BED0D /* ZitiIdentityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E21F4DCE44C7CFCFB4C2DAA6 /* ZitiIdentityTests.swift */; };
1112
297341CB58F1A35CA16AEA4D /* libz.1.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = AAFBA2462DDE1F6300B47602 /* libz.1.tbd */; };
1213
4081990387624D28257C0F29 /* EnrollModeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD854F0D1FEEBCA847B3970 /* EnrollModeTests.swift */; };
@@ -108,6 +109,8 @@
108109
5AE14C8C2471DDA000179365 /* libCZiti.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5AB6DF68244B7C3C00F4B4E0 /* libCZiti.a */; };
109110
5AF0C4112489987500CD4DAE /* ZitiClaims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AF0C4102489987500CD4DAE /* ZitiClaims.swift */; };
110111
5AF0C4122489987500CD4DAE /* ZitiClaims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AF0C4102489987500CD4DAE /* ZitiClaims.swift */; };
112+
83A7F07414EFD2894611AABF /* ZitiPostureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85301ED2D915DB71C27F228F /* ZitiPostureTests.swift */; };
113+
8537294C64AFB78FAA36BDD4 /* ZitiUrlClientConfigV1Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10590B6CE9FC16E8646002BB /* ZitiUrlClientConfigV1Tests.swift */; };
111114
A55E6A56BB6E78085DB2F6CD /* ZitiClaimsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51CD33D808C502A2CBC611D1 /* ZitiClaimsTests.swift */; };
112115
AA039EE02A963C53004D3F78 /* libllhttp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA039EDF2A963C53004D3F78 /* libllhttp.a */; };
113116
AA039EE22A963C9C004D3F78 /* libllhttp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA039EE12A963C9C004D3F78 /* libllhttp.a */; };
@@ -121,8 +124,11 @@
121124
AAFBA2482DDE20CA00B47602 /* libz.1.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = AAFBA2462DDE1F6300B47602 /* libz.1.tbd */; };
122125
AAFBA24A2DDE211800B47602 /* libz.1.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = AAFBA2492DDE210300B47602 /* libz.1.tbd */; };
123126
AAFBA24B2DDE221900B47602 /* libz.1.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = AAFBA2492DDE210300B47602 /* libz.1.tbd */; };
127+
AD59365D8C0738D64707DF21 /* ZitiHostConfigV1Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37173CE9DEB8C0224972518D /* ZitiHostConfigV1Tests.swift */; };
124128
BB14C8DC9EE744C7C9EAC9CF /* JWTProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5459DDBCB948CD7E608D7E8 /* JWTProviderTests.swift */; };
129+
D30C5785E35EC44D7207D41C /* ZitiMfaEnrollmentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E27FFBD4B1AF28D578B7B6A /* ZitiMfaEnrollmentTests.swift */; };
125130
E2C3EE6F48610C43BDC7440E /* ZitiEnrollerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A23D03F24C3A3853462CCE /* ZitiEnrollerTests.swift */; };
131+
FB8DF15ECCC628945D6E13A1 /* ZitiTunnelServerConfigV1Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B8CBAEB9ECAEBA3A713DE4 /* ZitiTunnelServerConfigV1Tests.swift */; };
126132
/* End PBXBuildFile section */
127133

128134
/* Begin PBXContainerItemProxy section */
@@ -194,6 +200,10 @@
194200
/* End PBXCopyFilesBuildPhase section */
195201

196202
/* Begin PBXFileReference section */
203+
0E27FFBD4B1AF28D578B7B6A /* ZitiMfaEnrollmentTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ZitiMfaEnrollmentTests.swift; sourceTree = "<group>"; };
204+
10590B6CE9FC16E8646002BB /* ZitiUrlClientConfigV1Tests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ZitiUrlClientConfigV1Tests.swift; sourceTree = "<group>"; };
205+
19B8CBAEB9ECAEBA3A713DE4 /* ZitiTunnelServerConfigV1Tests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ZitiTunnelServerConfigV1Tests.swift; sourceTree = "<group>"; };
206+
37173CE9DEB8C0224972518D /* ZitiHostConfigV1Tests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ZitiHostConfigV1Tests.swift; sourceTree = "<group>"; };
197207
4E13BFA0A49C64AC501330DD /* CZitiTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; name = CZitiTests.xctest; path = CZitiTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
198208
4FD854F0D1FEEBCA847B3970 /* EnrollModeTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = EnrollModeTests.swift; sourceTree = "<group>"; };
199209
51CD33D808C502A2CBC611D1 /* ZitiClaimsTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ZitiClaimsTests.swift; sourceTree = "<group>"; };
@@ -272,6 +282,8 @@
272282
5AF0C4102489987500CD4DAE /* ZitiClaims.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZitiClaims.swift; sourceTree = "<group>"; };
273283
5AFE864127E3C56000D47A47 /* libresolv.9.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.9.tbd; path = usr/lib/libresolv.9.tbd; sourceTree = SDKROOT; };
274284
5AFE864327E3C62800D47A47 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };
285+
85301ED2D915DB71C27F228F /* ZitiPostureTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ZitiPostureTests.swift; sourceTree = "<group>"; };
286+
9D2CE058E93C639D85230E5A /* ZitiInterceptConfigV1Tests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ZitiInterceptConfigV1Tests.swift; sourceTree = "<group>"; };
275287
A9A23D03F24C3A3853462CCE /* ZitiEnrollerTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ZitiEnrollerTests.swift; sourceTree = "<group>"; };
276288
AA039EDF2A963C53004D3F78 /* libllhttp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libllhttp.a; path = "deps/ziti-tunnel-sdk-c/build-macosx-arm64/vcpkg_installed/arm64-osx/lib/libllhttp.a"; sourceTree = "<group>"; };
277289
AA039EE12A963C9C004D3F78 /* libllhttp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libllhttp.a; path = "deps/ziti-tunnel-sdk-c/build-iphoneos-arm64/vcpkg_installed/arm64-ios/lib/libllhttp.a"; sourceTree = "<group>"; };
@@ -554,6 +566,12 @@
554566
C5459DDBCB948CD7E608D7E8 /* JWTProviderTests.swift */,
555567
A9A23D03F24C3A3853462CCE /* ZitiEnrollerTests.swift */,
556568
4FD854F0D1FEEBCA847B3970 /* EnrollModeTests.swift */,
569+
9D2CE058E93C639D85230E5A /* ZitiInterceptConfigV1Tests.swift */,
570+
37173CE9DEB8C0224972518D /* ZitiHostConfigV1Tests.swift */,
571+
19B8CBAEB9ECAEBA3A713DE4 /* ZitiTunnelServerConfigV1Tests.swift */,
572+
10590B6CE9FC16E8646002BB /* ZitiUrlClientConfigV1Tests.swift */,
573+
85301ED2D915DB71C27F228F /* ZitiPostureTests.swift */,
574+
0E27FFBD4B1AF28D578B7B6A /* ZitiMfaEnrollmentTests.swift */,
557575
);
558576
name = CZitiTests;
559577
path = CZitiTests;
@@ -889,6 +907,12 @@
889907
BB14C8DC9EE744C7C9EAC9CF /* JWTProviderTests.swift in Sources */,
890908
E2C3EE6F48610C43BDC7440E /* ZitiEnrollerTests.swift in Sources */,
891909
4081990387624D28257C0F29 /* EnrollModeTests.swift in Sources */,
910+
1173FC5AE4A751591E38F2B4 /* ZitiInterceptConfigV1Tests.swift in Sources */,
911+
AD59365D8C0738D64707DF21 /* ZitiHostConfigV1Tests.swift in Sources */,
912+
FB8DF15ECCC628945D6E13A1 /* ZitiTunnelServerConfigV1Tests.swift in Sources */,
913+
8537294C64AFB78FAA36BDD4 /* ZitiUrlClientConfigV1Tests.swift in Sources */,
914+
83A7F07414EFD2894611AABF /* ZitiPostureTests.swift in Sources */,
915+
D30C5785E35EC44D7207D41C /* ZitiMfaEnrollmentTests.swift in Sources */,
892916
);
893917
runOnlyForDeploymentPostprocessing = 0;
894918
};
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
Copyright NetFoundry Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
import XCTest
17+
@testable import CZiti
18+
19+
class ZitiHostConfigV1Tests: XCTestCase {
20+
21+
func testDecodeProtocolMapsToProto() throws {
22+
// "protocol" is a reserved word in Swift, so the type maps the JSON "protocol" key to "proto"
23+
let json = """
24+
{"protocol":"tcp","address":"10.0.0.1","port":8080}
25+
"""
26+
let cfg = try JSONDecoder().decode(ZitiHostConfigV1.self, from: json.data(using: .utf8)!)
27+
XCTAssertEqual(cfg.proto, "tcp")
28+
XCTAssertEqual(cfg.address, "10.0.0.1")
29+
XCTAssertEqual(cfg.port, 8080)
30+
}
31+
32+
func testEncodeUsesProtocolKey() throws {
33+
let json = """
34+
{"protocol":"udp","address":"0.0.0.0","port":53}
35+
"""
36+
let cfg = try JSONDecoder().decode(ZitiHostConfigV1.self, from: json.data(using: .utf8)!)
37+
let encoded = try JSONEncoder().encode(cfg)
38+
let dict = try JSONSerialization.jsonObject(with: encoded) as! [String: Any]
39+
XCTAssertEqual(dict["protocol"] as? String, "udp")
40+
XCTAssertNil(dict["proto"])
41+
}
42+
43+
func testDecodeFullConfig() throws {
44+
let json = """
45+
{
46+
"protocol": "tcp",
47+
"forwardProtocol": true,
48+
"allowedProtocols": ["tcp", "udp"],
49+
"address": "0.0.0.0",
50+
"forwardAddress": false,
51+
"allowedAddresses": ["192.168.1.0/24"],
52+
"allowedSourceAddresses": ["10.0.0.0/8"],
53+
"port": 8080,
54+
"forwardPort": true,
55+
"allowedPortRanges": [{"low": 80, "high": 443}],
56+
"listenOptions": {
57+
"connectTimeoutSeconds": 30,
58+
"maxConnections": 1000,
59+
"identity": "host-id",
60+
"bindUsingEdgeIdentity": true
61+
}
62+
}
63+
"""
64+
let cfg = try JSONDecoder().decode(ZitiHostConfigV1.self, from: json.data(using: .utf8)!)
65+
66+
XCTAssertEqual(cfg.proto, "tcp")
67+
XCTAssertEqual(cfg.forwardProtocol, true)
68+
XCTAssertEqual(cfg.allowedProtocols, ["tcp", "udp"])
69+
XCTAssertEqual(cfg.address, "0.0.0.0")
70+
XCTAssertEqual(cfg.forwardAddress, false)
71+
XCTAssertEqual(cfg.allowedAddresses, ["192.168.1.0/24"])
72+
XCTAssertEqual(cfg.allowedSourceAddresses, ["10.0.0.0/8"])
73+
XCTAssertEqual(cfg.port, 8080)
74+
XCTAssertEqual(cfg.forwardPort, true)
75+
XCTAssertEqual(cfg.allowedPortRanges?.count, 1)
76+
XCTAssertEqual(cfg.allowedPortRanges?[0].low, 80)
77+
XCTAssertEqual(cfg.allowedPortRanges?[0].high, 443)
78+
XCTAssertEqual(cfg.listenOptions?.connectTimeoutSeconds, 30)
79+
XCTAssertEqual(cfg.listenOptions?.maxConnections, 1000)
80+
XCTAssertEqual(cfg.listenOptions?.identity, "host-id")
81+
XCTAssertEqual(cfg.listenOptions?.bindUsingEdgeIdentity, true)
82+
}
83+
84+
func testDecodeMinimalConfig() throws {
85+
let json = """
86+
{}
87+
"""
88+
let cfg = try JSONDecoder().decode(ZitiHostConfigV1.self, from: json.data(using: .utf8)!)
89+
XCTAssertNil(cfg.proto)
90+
XCTAssertNil(cfg.address)
91+
XCTAssertNil(cfg.port)
92+
XCTAssertNil(cfg.listenOptions)
93+
}
94+
95+
func testCodableRoundTrip() throws {
96+
let json = """
97+
{"protocol":"tcp","address":"1.2.3.4","port":8080,"listenOptions":{"identity":"x","maxConnections":10}}
98+
"""
99+
let original = try JSONDecoder().decode(ZitiHostConfigV1.self, from: json.data(using: .utf8)!)
100+
let encoded = try JSONEncoder().encode(original)
101+
let decoded = try JSONDecoder().decode(ZitiHostConfigV1.self, from: encoded)
102+
103+
XCTAssertEqual(decoded.proto, original.proto)
104+
XCTAssertEqual(decoded.address, original.address)
105+
XCTAssertEqual(decoded.port, original.port)
106+
XCTAssertEqual(decoded.listenOptions?.identity, original.listenOptions?.identity)
107+
XCTAssertEqual(decoded.listenOptions?.maxConnections, original.listenOptions?.maxConnections)
108+
}
109+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
Copyright NetFoundry Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
import XCTest
17+
@testable import CZiti
18+
19+
class ZitiInterceptConfigV1Tests: XCTestCase {
20+
21+
func testDecodeFullConfig() throws {
22+
let json = """
23+
{
24+
"protocols": ["tcp", "udp"],
25+
"addresses": ["192.168.1.0/24", "10.0.0.0/8", "example.com"],
26+
"portRanges": [
27+
{"low": 80, "high": 443},
28+
{"low": 8000, "high": 9000}
29+
],
30+
"dialOptions": {
31+
"identity": "my-id",
32+
"connectTimeoutSeconds": 30
33+
},
34+
"sourceIp": "192.168.1.1"
35+
}
36+
"""
37+
let cfg = try JSONDecoder().decode(ZitiInterceptConfigV1.self, from: json.data(using: .utf8)!)
38+
39+
XCTAssertEqual(cfg.protocols, ["tcp", "udp"])
40+
XCTAssertEqual(cfg.addresses, ["192.168.1.0/24", "10.0.0.0/8", "example.com"])
41+
XCTAssertEqual(cfg.portRanges.count, 2)
42+
XCTAssertEqual(cfg.portRanges[0].low, 80)
43+
XCTAssertEqual(cfg.portRanges[0].high, 443)
44+
XCTAssertEqual(cfg.portRanges[1].low, 8000)
45+
XCTAssertEqual(cfg.portRanges[1].high, 9000)
46+
XCTAssertEqual(cfg.dialOptions?.identity, "my-id")
47+
XCTAssertEqual(cfg.dialOptions?.connectTimeoutSeconds, 30)
48+
XCTAssertEqual(cfg.sourceIp, "192.168.1.1")
49+
}
50+
51+
func testDecodeWithoutOptionals() throws {
52+
let json = """
53+
{
54+
"protocols": ["tcp"],
55+
"addresses": ["10.0.0.1"],
56+
"portRanges": [{"low": 80, "high": 80}]
57+
}
58+
"""
59+
let cfg = try JSONDecoder().decode(ZitiInterceptConfigV1.self, from: json.data(using: .utf8)!)
60+
XCTAssertNil(cfg.dialOptions)
61+
XCTAssertNil(cfg.sourceIp)
62+
}
63+
64+
func testDecodeEmptyPortRanges() throws {
65+
let json = """
66+
{
67+
"protocols": ["tcp"],
68+
"addresses": ["x.y.z"],
69+
"portRanges": []
70+
}
71+
"""
72+
let cfg = try JSONDecoder().decode(ZitiInterceptConfigV1.self, from: json.data(using: .utf8)!)
73+
XCTAssertEqual(cfg.portRanges.count, 0)
74+
}
75+
76+
func testCodableRoundTrip() throws {
77+
let json = """
78+
{"protocols":["tcp"],"addresses":["10.0.0.1"],"portRanges":[{"low":80,"high":443}],"sourceIp":"1.2.3.4"}
79+
"""
80+
let original = try JSONDecoder().decode(ZitiInterceptConfigV1.self, from: json.data(using: .utf8)!)
81+
let encoded = try JSONEncoder().encode(original)
82+
let decoded = try JSONDecoder().decode(ZitiInterceptConfigV1.self, from: encoded)
83+
84+
XCTAssertEqual(decoded.protocols, original.protocols)
85+
XCTAssertEqual(decoded.addresses, original.addresses)
86+
XCTAssertEqual(decoded.portRanges.count, original.portRanges.count)
87+
XCTAssertEqual(decoded.sourceIp, original.sourceIp)
88+
}
89+
90+
func testDialOptionsAllNil() throws {
91+
let json = """
92+
{
93+
"protocols": ["tcp"],
94+
"addresses": ["x"],
95+
"portRanges": [{"low": 1, "high": 1}],
96+
"dialOptions": {}
97+
}
98+
"""
99+
let cfg = try JSONDecoder().decode(ZitiInterceptConfigV1.self, from: json.data(using: .utf8)!)
100+
XCTAssertNotNil(cfg.dialOptions)
101+
XCTAssertNil(cfg.dialOptions?.identity)
102+
XCTAssertNil(cfg.dialOptions?.connectTimeoutSeconds)
103+
}
104+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
Copyright NetFoundry Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
import XCTest
17+
@testable import CZiti
18+
19+
class ZitiMfaEnrollmentTests: XCTestCase {
20+
21+
func testDecodeFull() throws {
22+
let json = """
23+
{
24+
"isVerified": true,
25+
"provisioningUrl": "otpauth://totp/user@example.com?secret=ABC",
26+
"recoveryCodes": ["code-1", "code-2", "code-3"]
27+
}
28+
"""
29+
let mfa = try JSONDecoder().decode(ZitiMfaEnrollment.self, from: json.data(using: .utf8)!)
30+
XCTAssertEqual(mfa.isVerified, true)
31+
XCTAssertEqual(mfa.provisioningUrl, "otpauth://totp/user@example.com?secret=ABC")
32+
XCTAssertEqual(mfa.recoveryCodes, ["code-1", "code-2", "code-3"])
33+
}
34+
35+
func testDecodeAllOptionalsMissing() throws {
36+
let json = """
37+
{}
38+
"""
39+
let mfa = try JSONDecoder().decode(ZitiMfaEnrollment.self, from: json.data(using: .utf8)!)
40+
XCTAssertNil(mfa.isVerified)
41+
XCTAssertNil(mfa.provisioningUrl)
42+
XCTAssertNil(mfa.recoveryCodes)
43+
}
44+
45+
func testDecodeEmptyRecoveryCodes() throws {
46+
let json = """
47+
{"isVerified":false,"recoveryCodes":[]}
48+
"""
49+
let mfa = try JSONDecoder().decode(ZitiMfaEnrollment.self, from: json.data(using: .utf8)!)
50+
XCTAssertEqual(mfa.isVerified, false)
51+
XCTAssertEqual(mfa.recoveryCodes, [])
52+
}
53+
54+
func testRoundTrip() throws {
55+
let json = """
56+
{"isVerified":true,"provisioningUrl":"x","recoveryCodes":["a","b"]}
57+
"""
58+
let original = try JSONDecoder().decode(ZitiMfaEnrollment.self, from: json.data(using: .utf8)!)
59+
let encoded = try JSONEncoder().encode(original)
60+
let decoded = try JSONDecoder().decode(ZitiMfaEnrollment.self, from: encoded)
61+
XCTAssertEqual(decoded.isVerified, original.isVerified)
62+
XCTAssertEqual(decoded.provisioningUrl, original.provisioningUrl)
63+
XCTAssertEqual(decoded.recoveryCodes, original.recoveryCodes)
64+
}
65+
}

0 commit comments

Comments
 (0)