Skip to content

Commit e1a4f4b

Browse files
authored
test: add unit tests for Device, Command, Collection, and String extensions (#144)
1 parent 4c323d8 commit e1a4f4b

5 files changed

Lines changed: 316 additions & 0 deletions

File tree

MiniSim.xcodeproj/project.pbxproj

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

99
/* Begin PBXBuildFile section */
10+
162A369BC040E62A74C782D1 /* CollectionGetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 912D7A2027F3DDA86839E7AE /* CollectionGetTests.swift */; };
11+
16B53AB50DDD40DC4880CCB8 /* DeviceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 470EFF3B34FB31AC5A22B024 /* DeviceTests.swift */; };
12+
2549AC06811CB09AF7D5A4DF /* CommandTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63E9205F1463934FDB7D92FF /* CommandTests.swift */; };
1013
4AFACC742AD730BE00EC369F /* SubMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AFACC732AD730BE00EC369F /* SubMenuItem.swift */; };
1114
4AFACC762AD73D7900EC369F /* NSMenuItem+ConvenienceInit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AFACC752AD73D7900EC369F /* NSMenuItem+ConvenienceInit.swift */; };
1215
4AFACC782AD74E9000EC369F /* DeviceListSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AFACC772AD74E9000EC369F /* DeviceListSection.swift */; };
@@ -108,6 +111,7 @@
108111
76F2A9172991B7B6002D4EF6 /* ViewModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76F2A9162991B7B6002D4EF6 /* ViewModifiers.swift */; };
109112
76FCABAB29B390D5003BBF9A /* Collection+get.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76FCABAA29B390D5003BBF9A /* Collection+get.swift */; };
110113
7D4142B4F3AF1D150D9222BD /* DeviceFamily.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F78DD26087D5448AAB2CC3B /* DeviceFamily.swift */; };
114+
7D850183B2E53A3E4F17994A /* StringMatchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A9C6AA804E851167EA01B17 /* StringMatchTests.swift */; };
111115
9B225A9C2C7E360D002620BA /* DeviceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B225A9B2C7E360D002620BA /* DeviceType.swift */; };
112116
/* End PBXBuildFile section */
113117

@@ -122,6 +126,7 @@
122126
/* End PBXContainerItemProxy section */
123127

124128
/* Begin PBXFileReference section */
129+
470EFF3B34FB31AC5A22B024 /* DeviceTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DeviceTests.swift; sourceTree = "<group>"; };
125130
4AFACC732AD730BE00EC369F /* SubMenuItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubMenuItem.swift; sourceTree = "<group>"; };
126131
4AFACC752AD73D7900EC369F /* NSMenuItem+ConvenienceInit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMenuItem+ConvenienceInit.swift"; sourceTree = "<group>"; };
127132
4AFACC772AD74E9000EC369F /* DeviceListSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceListSection.swift; sourceTree = "<group>"; };
@@ -131,6 +136,8 @@
131136
551B88292B1385E900B8D325 /* Terminal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Terminal.swift; sourceTree = "<group>"; };
132137
55CDB0772B1B6D24002418D7 /* TerminalApps.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalApps.swift; sourceTree = "<group>"; };
133138
5F78DD26087D5448AAB2CC3B /* DeviceFamily.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DeviceFamily.swift; sourceTree = "<group>"; };
139+
63E9205F1463934FDB7D92FF /* CommandTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CommandTests.swift; sourceTree = "<group>"; };
140+
6A9C6AA804E851167EA01B17 /* StringMatchTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StringMatchTests.swift; sourceTree = "<group>"; };
134141
760554A22C085BEA001607FE /* Thread+Asserts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Thread+Asserts.swift"; sourceTree = "<group>"; };
135142
76059BF42AD4361C0008D38B /* SetupPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupPreferences.swift; sourceTree = "<group>"; };
136143
76059BF62AD449DC0008D38B /* OnboardingHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingHeader.swift; sourceTree = "<group>"; };
@@ -219,6 +226,7 @@
219226
76F2A913299050F9002D4EF6 /* UserDefaults+Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Configuration.swift"; sourceTree = "<group>"; };
220227
76F2A9162991B7B6002D4EF6 /* ViewModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModifiers.swift; sourceTree = "<group>"; };
221228
76FCABAA29B390D5003BBF9A /* Collection+get.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+get.swift"; sourceTree = "<group>"; };
229+
912D7A2027F3DDA86839E7AE /* CollectionGetTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CollectionGetTests.swift; sourceTree = "<group>"; };
222230
9B225A9B2C7E360D002620BA /* DeviceType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceType.swift; sourceTree = "<group>"; };
223231
/* End PBXFileReference section */
224232

@@ -463,6 +471,10 @@
463471
76BF0AF32C90A74E003BE568 /* AppleUtilsTests.swift */,
464472
76BF0AF52C90AB03003BE568 /* DeviceDiscoveryTests.swift */,
465473
76BF0AF72C90ACF2003BE568 /* ActionFactoryTests.swift */,
474+
470EFF3B34FB31AC5A22B024 /* DeviceTests.swift */,
475+
6A9C6AA804E851167EA01B17 /* StringMatchTests.swift */,
476+
912D7A2027F3DDA86839E7AE /* CollectionGetTests.swift */,
477+
63E9205F1463934FDB7D92FF /* CommandTests.swift */,
466478
);
467479
path = MiniSimTests;
468480
sourceTree = "<group>";
@@ -741,6 +753,10 @@
741753
76B70F7E2B0D361A009D87A4 /* UserDefaultsTests.swift in Sources */,
742754
760DEACE2B0DFB6600253576 /* ShellStub.swift in Sources */,
743755
76B70F822B0D50FE009D87A4 /* ADBTests.swift in Sources */,
756+
16B53AB50DDD40DC4880CCB8 /* DeviceTests.swift in Sources */,
757+
7D850183B2E53A3E4F17994A /* StringMatchTests.swift in Sources */,
758+
162A369BC040E62A74C782D1 /* CollectionGetTests.swift in Sources */,
759+
2549AC06811CB09AF7D5A4DF /* CommandTests.swift in Sources */,
744760
);
745761
runOnlyForDeploymentPostprocessing = 0;
746762
};
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import XCTest
2+
3+
@testable import MiniSim
4+
5+
final class CollectionGetTests: XCTestCase {
6+
func testGetAtValidIndex() {
7+
let array = ["a", "b", "c"]
8+
9+
XCTAssertEqual(array.get(at: 0), "a")
10+
XCTAssertEqual(array.get(at: 1), "b")
11+
XCTAssertEqual(array.get(at: 2), "c")
12+
}
13+
14+
func testGetAtInvalidIndex() {
15+
let array = ["a", "b", "c"]
16+
17+
XCTAssertNil(array.get(at: 3))
18+
XCTAssertNil(array.get(at: 100))
19+
}
20+
21+
func testGetOnEmptyCollection() {
22+
let array: [String] = []
23+
24+
XCTAssertNil(array.get(at: 0))
25+
}
26+
27+
func testGetWithDifferentTypes() {
28+
let intArray = [1, 2, 3]
29+
XCTAssertEqual(intArray.get(at: 1), 2)
30+
31+
let deviceArray = [
32+
Device(name: "iPhone", identifier: "uuid1", platform: .ios, type: .virtual),
33+
Device(name: "Pixel", identifier: "uuid2", platform: .android, type: .virtual)
34+
]
35+
XCTAssertEqual(deviceArray.get(at: 0)?.name, "iPhone")
36+
XCTAssertEqual(deviceArray.get(at: 1)?.platform, .android)
37+
XCTAssertNil(deviceArray.get(at: 2))
38+
}
39+
40+
func testGetOnDictionary() {
41+
let dict = ["a": 1, "b": 2]
42+
let keys = Array(dict.keys).sorted()
43+
44+
XCTAssertNotNil(keys.get(at: 0))
45+
XCTAssertNil(keys.get(at: 10))
46+
}
47+
}

MiniSimTests/CommandTests.swift

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import XCTest
2+
3+
@testable import MiniSim
4+
5+
final class CommandTests: XCTestCase {
6+
func testEncodingDecoding() throws {
7+
let command = Command(
8+
name: "Test Command",
9+
command: "adb devices",
10+
icon: "terminal",
11+
platform: .android,
12+
needBootedDevice: true,
13+
bootsDevice: false,
14+
tag: 42
15+
)
16+
17+
let encoded = try JSONEncoder().encode(command)
18+
let decoded = try JSONDecoder().decode(Command.self, from: encoded)
19+
20+
XCTAssertEqual(decoded.name, command.name)
21+
XCTAssertEqual(decoded.command, command.command)
22+
XCTAssertEqual(decoded.icon, command.icon)
23+
XCTAssertEqual(decoded.platform, command.platform)
24+
XCTAssertEqual(decoded.needBootedDevice, command.needBootedDevice)
25+
XCTAssertEqual(decoded.bootsDevice, command.bootsDevice)
26+
XCTAssertEqual(decoded.tag, command.tag)
27+
}
28+
29+
func testDecodingOptionalFieldsNil() throws {
30+
let json = """
31+
{
32+
"id": "550e8400-e29b-41d4-a716-446655440000",
33+
"name": "Test",
34+
"command": "echo test",
35+
"icon": "star",
36+
"platform": "ios",
37+
"needBootedDevice": false
38+
}
39+
"""
40+
41+
let data = json.data(using: .utf8)!
42+
let decoded = try JSONDecoder().decode(Command.self, from: data)
43+
44+
XCTAssertEqual(decoded.name, "Test")
45+
XCTAssertEqual(decoded.platform, .ios)
46+
XCTAssertNil(decoded.bootsDevice)
47+
XCTAssertNil(decoded.tag)
48+
}
49+
50+
func testDecodingOptionalFieldsPresent() throws {
51+
let json = """
52+
{
53+
"id": "550e8400-e29b-41d4-a716-446655440000",
54+
"name": "Test",
55+
"command": "echo test",
56+
"icon": "star",
57+
"platform": "android",
58+
"needBootedDevice": true,
59+
"bootsDevice": true,
60+
"tag": 99
61+
}
62+
"""
63+
64+
let data = json.data(using: .utf8)!
65+
let decoded = try JSONDecoder().decode(Command.self, from: data)
66+
67+
XCTAssertEqual(decoded.bootsDevice, true)
68+
XCTAssertEqual(decoded.tag, 99)
69+
}
70+
71+
func testCommandHashable() {
72+
let command1 = Command(
73+
name: "Test",
74+
command: "echo",
75+
icon: "star",
76+
platform: .ios,
77+
needBootedDevice: false
78+
)
79+
80+
let command2 = Command(
81+
name: "Test",
82+
command: "echo",
83+
icon: "star",
84+
platform: .ios,
85+
needBootedDevice: false
86+
)
87+
88+
// Different UUIDs, so not equal
89+
XCTAssertNotEqual(command1, command2)
90+
91+
// Same command in set should work
92+
var commandSet: Set<Command> = []
93+
commandSet.insert(command1)
94+
commandSet.insert(command2)
95+
XCTAssertEqual(commandSet.count, 2)
96+
}
97+
98+
func testCommandIdentifiable() {
99+
let command = Command(
100+
name: "Test",
101+
command: "echo",
102+
icon: "star",
103+
platform: .ios,
104+
needBootedDevice: false
105+
)
106+
107+
XCTAssertNotNil(command.id)
108+
}
109+
}

MiniSimTests/DeviceTests.swift

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import XCTest
2+
3+
@testable import MiniSim
4+
5+
final class DeviceTests: XCTestCase {
6+
func testDisplayNameIOSWithVersion() {
7+
let device = Device(
8+
name: "iPhone 15 Pro",
9+
version: "iOS 17.5",
10+
identifier: "test-uuid",
11+
booted: false,
12+
platform: .ios,
13+
type: .virtual
14+
)
15+
16+
XCTAssertEqual(device.displayName, "iPhone 15 Pro - (iOS 17.5)")
17+
}
18+
19+
func testDisplayNameIOSWithoutVersion() {
20+
let device = Device(
21+
name: "iPhone 15 Pro",
22+
version: nil,
23+
identifier: "test-uuid",
24+
booted: false,
25+
platform: .ios,
26+
type: .virtual
27+
)
28+
29+
XCTAssertEqual(device.displayName, "iPhone 15 Pro")
30+
}
31+
32+
func testDisplayNameAndroid() {
33+
let device = Device(
34+
name: "Pixel_5_API_33",
35+
version: "13",
36+
identifier: "emulator-5554",
37+
booted: true,
38+
platform: .android,
39+
type: .virtual
40+
)
41+
42+
XCTAssertEqual(device.displayName, "Pixel_5_API_33")
43+
}
44+
45+
func testEncodingDecoding() throws {
46+
let device = Device(
47+
name: "iPhone 15 Pro",
48+
version: "iOS 17.5",
49+
identifier: "test-uuid",
50+
booted: true,
51+
platform: .ios,
52+
type: .virtual
53+
)
54+
55+
let encoded = try JSONEncoder().encode(device)
56+
let decoded = try JSONDecoder().decode(Device.self, from: encoded)
57+
58+
XCTAssertEqual(decoded.name, device.name)
59+
XCTAssertEqual(decoded.version, device.version)
60+
XCTAssertEqual(decoded.identifier, device.identifier)
61+
XCTAssertEqual(decoded.booted, device.booted)
62+
XCTAssertEqual(decoded.platform, device.platform)
63+
XCTAssertEqual(decoded.type, device.type)
64+
}
65+
66+
func testEncodingIncludesDisplayName() throws {
67+
let device = Device(
68+
name: "iPhone 15",
69+
version: "iOS 17.5",
70+
identifier: "uuid",
71+
booted: false,
72+
platform: .ios,
73+
type: .virtual
74+
)
75+
76+
let encoded = try JSONEncoder().encode(device)
77+
let json = try JSONSerialization.jsonObject(with: encoded) as? [String: Any]
78+
79+
XCTAssertEqual(json?["displayName"] as? String, "iPhone 15 - (iOS 17.5)")
80+
}
81+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import XCTest
2+
3+
@testable import MiniSim
4+
5+
final class StringMatchTests: XCTestCase {
6+
func testMatchWithValidPattern() {
7+
let input = "iPhone 15 Pro"
8+
let matches = input.match("iPhone")
9+
10+
XCTAssertEqual(matches.count, 1)
11+
XCTAssertEqual(matches.first?.first, "iPhone")
12+
}
13+
14+
func testMatchWithNoMatch() {
15+
let input = "iPhone 15 Pro"
16+
let matches = input.match("Android")
17+
18+
XCTAssertTrue(matches.isEmpty)
19+
}
20+
21+
func testMatchWithMultipleMatches() {
22+
let input = "abc123def456ghi789"
23+
let matches = input.match("[0-9]+")
24+
25+
XCTAssertEqual(matches.count, 3)
26+
XCTAssertEqual(matches[0].first, "123")
27+
XCTAssertEqual(matches[1].first, "456")
28+
XCTAssertEqual(matches[2].first, "789")
29+
}
30+
31+
func testMatchWithCaptureGroups() {
32+
let input = "emulator-5554"
33+
let matches = input.match("(emulator)-([0-9]+)")
34+
35+
XCTAssertEqual(matches.count, 1)
36+
XCTAssertEqual(matches[0][0], "emulator-5554")
37+
XCTAssertEqual(matches[0][1], "emulator")
38+
XCTAssertEqual(matches[0][2], "5554")
39+
}
40+
41+
func testMatchWithEmptyString() {
42+
let input = ""
43+
let matches = input.match("[a-z]+")
44+
45+
XCTAssertTrue(matches.isEmpty)
46+
}
47+
48+
func testMatchUUIDPattern() {
49+
let input = "iPhone 15 (957C8A2F-4C12-4732-A4E9-37F8FDD35E3B) (Booted)"
50+
let matches = input.match("[A-F0-9-]{36}")
51+
52+
XCTAssertEqual(matches.count, 1)
53+
XCTAssertEqual(matches.first?.first, "957C8A2F-4C12-4732-A4E9-37F8FDD35E3B")
54+
}
55+
56+
func testMatchEmulatorIdPattern() {
57+
let input = "emulator-5554 device"
58+
let matches = input.match("^emulator-[0-9]+")
59+
60+
XCTAssertEqual(matches.count, 1)
61+
XCTAssertEqual(matches.first?.first, "emulator-5554")
62+
}
63+
}

0 commit comments

Comments
 (0)