Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 44997e6

Browse files
committedDec 16, 2024·
ci: add test, fmt, lint workflows
1 parent eb61235 commit 44997e6

File tree

24 files changed

+241
-138
lines changed

24 files changed

+241
-138
lines changed
 

‎.github/workflows/ci.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: ci
2+
3+
on:
4+
pull_request:
5+
paths-ignore:
6+
- "README.md"
7+
push:
8+
branches:
9+
- main
10+
paths-ignore:
11+
- "README.md"
12+
13+
14+
permissions:
15+
contents: read
16+
17+
jobs:
18+
test:
19+
name: test
20+
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
24+
with:
25+
fetch-depth: 1
26+
- name: Switch XCode Version
27+
uses: maxim-lobanov/setup-xcode@v1
28+
with:
29+
xcode-version: '16.0.0'
30+
- run: |
31+
make test
32+
format:
33+
name: fmt
34+
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
35+
steps:
36+
- name: Checkout
37+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
38+
with:
39+
fetch-depth: 1
40+
- run: |
41+
make fmt
42+
lint:
43+
name: lint
44+
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
45+
steps:
46+
- name: Checkout
47+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
48+
with:
49+
fetch-depth: 1
50+
- name: Install Swiftlint
51+
run: |
52+
brew install swiftlint
53+
- run: |
54+
make lint

‎Coder Desktop/.swiftlint.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
disabled_rules:
22
- todo
33
- trailing_comma
4+
- blanket_disable_command # Used by Protobuf
5+
- opening_brace # Handled by SwiftFormat
46
type_name:
57
allowed_symbols: "_"
68
identifier_name:
79
allowed_symbols: "_"
10+
min_length: 1

‎Coder Desktop/Coder Desktop.xcodeproj/project.pbxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,7 @@
721721
CURRENT_PROJECT_VERSION = 1;
722722
DEVELOPMENT_TEAM = 4399GN35BJ;
723723
GENERATE_INFOPLIST_FILE = YES;
724+
MACOSX_DEPLOYMENT_TARGET = 14.6;
724725
MARKETING_VERSION = 1.0;
725726
PRODUCT_BUNDLE_IDENTIFIER = "com.coder.Coder-DesktopUITests";
726727
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -737,6 +738,7 @@
737738
CURRENT_PROJECT_VERSION = 1;
738739
DEVELOPMENT_TEAM = 4399GN35BJ;
739740
GENERATE_INFOPLIST_FILE = YES;
741+
MACOSX_DEPLOYMENT_TARGET = 14.6;
740742
MARKETING_VERSION = 1.0;
741743
PRODUCT_BUNDLE_IDENTIFIER = "com.coder.Coder-DesktopUITests";
742744
PRODUCT_NAME = "$(TARGET_NAME)";

‎Coder Desktop/Coder Desktop.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Coder Desktop/Coder Desktop.xctestplan

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
}
2626
},
2727
{
28+
"enabled" : false,
2829
"parallelizable" : true,
2930
"target" : {
3031
"containerPath" : "container:Coder Desktop.xcodeproj",

‎Coder Desktop/Coder Desktop/Theme.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ enum Theme {
88

99
static let rectCornerRadius: CGFloat = 4
1010
}
11+
1112
static let defaultVisibleAgents = 5
1213
}

‎Coder Desktop/Coder Desktop/Views/Agents.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ struct Agents<VPN: VPNService, S: Session>: View {
66
@State private var viewAll = false
77
private let defaultVisibleRows = 5
88

9-
internal let inspection = Inspection<Self>()
9+
let inspection = Inspection<Self>()
1010

1111
var body: some View {
1212
Group {

‎Coder Desktop/Coder Desktop/Views/LoginForm.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ struct LoginForm<C: Client, S: Session>: View {
1111
@State private var loading: Bool = false
1212
@FocusState private var focusedField: LoginField?
1313

14-
internal let inspection = Inspection<Self>()
14+
let inspection = Inspection<Self>()
1515

1616
var body: some View {
1717
VStack {
@@ -56,7 +56,7 @@ struct LoginForm<C: Client, S: Session>: View {
5656
.onReceive(inspection.notice) { self.inspection.visit(self, $0) } // ViewInspector
5757
}
5858

59-
internal func submit() async {
59+
func submit() async {
6060
loginError = nil
6161
guard sessionToken != "" else {
6262
loginError = .invalidToken
@@ -67,7 +67,7 @@ struct LoginForm<C: Client, S: Session>: View {
6767
return
6868
}
6969
loading = true
70-
defer { loading = false}
70+
defer { loading = false }
7171
let client = C(url: url, token: sessionToken)
7272
do {
7373
_ = try await client.user("me")
@@ -135,8 +135,8 @@ struct LoginForm<C: Client, S: Session>: View {
135135
Button("Sign In") {
136136
Task { await submit() }
137137
}
138-
.buttonStyle(.borderedProminent)
139-
.keyboardShortcut(.defaultAction)
138+
.buttonStyle(.borderedProminent)
139+
.keyboardShortcut(.defaultAction)
140140
}.padding(.top, 5)
141141
}
142142
}

‎Coder Desktop/Coder Desktop/Views/Util.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Combine
22

33
// This is required for inspecting stateful views
4-
internal final class Inspection<V> {
4+
final class Inspection<V> {
55
let notice = PassthroughSubject<UInt, Never>()
66
var callbacks = [UInt: (V) -> Void]()
77

‎Coder Desktop/Coder Desktop/Views/VPNMenu.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
44
@EnvironmentObject var vpn: VPN
55
@EnvironmentObject var session: S
66

7-
internal let inspection = Inspection<Self>()
7+
let inspection = Inspection<Self>()
88

99
var body: some View {
1010
// Main stack

‎Coder Desktop/Coder Desktop/Views/VPNState.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import SwiftUI
33
struct VPNState<VPN: VPNService>: View {
44
@EnvironmentObject var vpn: VPN
55

6-
internal let inspection = Inspection<Self>()
6+
let inspection = Inspection<Self>()
77

88
var body: some View {
99
Group {

‎Coder Desktop/Coder DesktopTests/AgentsTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
@testable import Coder_Desktop
2+
import SwiftUI
23
import Testing
34
import ViewInspector
4-
import SwiftUI
55

66
@Suite(.timeLimit(.minutes(1)))
77
struct AgentsTests {
@@ -47,7 +47,7 @@ struct AgentsTests {
4747

4848
let forEach = try view.inspect().find(ViewType.ForEach.self)
4949
#expect(forEach.count == Theme.defaultVisibleAgents)
50-
#expect(throws: Never.self) { try view.inspect().find(link: "a1.coder")}
50+
#expect(throws: Never.self) { try view.inspect().find(link: "a1.coder") }
5151
}
5252

5353
@Test

‎Coder Desktop/Coder DesktopTests/LoginFormTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
@testable import Coder_Desktop
2-
import ViewInspector
3-
import Testing
42
import SwiftUI
3+
import Testing
4+
import ViewInspector
55

66
@Suite(.timeLimit(.minutes(1)))
77
struct LoginTests {

‎Coder Desktop/Coder DesktopTests/Util.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ struct MockClient: Client {
6767
}
6868

6969
struct MockErrorClient: Client {
70-
init(url: URL, token: String?) {}
71-
func user(_ ident: String) async throws -> Coder_Desktop.User {
70+
init(url _: URL, token _: String?) {}
71+
func user(_: String) async throws -> Coder_Desktop.User {
7272
throw ClientError.badResponse
7373
}
7474
}
7575

76-
extension Inspection: @retroactive InspectionEmissary { }
76+
extension Inspection: @retroactive InspectionEmissary {}

‎Coder Desktop/Coder DesktopTests/VPNMenuTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
@testable import Coder_Desktop
2+
import SwiftUI
23
import Testing
34
import ViewInspector
4-
import SwiftUI
55

66
@Suite(.timeLimit(.minutes(1)))
77
struct VPNMenuTests {

‎Coder Desktop/Coder DesktopTests/VPNStateTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
@testable import Coder_Desktop
2-
import ViewInspector
3-
import Testing
42
import SwiftUI
3+
import Testing
4+
import ViewInspector
55

66
@Suite(.timeLimit(.minutes(1)))
77
struct VPNStateTests {

‎Coder Desktop/Coder DesktopUITests/Coder_DesktopUITests.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ final class Coder_DesktopUITests: XCTestCase {
77
// In UI tests it is usually best to stop immediately when a failure occurs.
88
continueAfterFailure = false
99

10-
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
10+
// In UI tests it’s important to set the initial state - such as
11+
// interface orientation - required for your tests before they run. The setUp method is a good place to do this.
1112
}
1213

1314
override func tearDownWithError() throws {

‎Coder Desktop/Coder DesktopUITests/Coder_DesktopUITestsLaunchTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import XCTest
22

33
final class Coder_DesktopUITestsLaunchTests: XCTestCase {
4-
override class var runsForEachTargetApplicationUIConfiguration: Bool {
4+
override static var runsForEachTargetApplicationUIConfiguration: Bool {
55
true
66
}
77

‎Coder Desktop/Proto/Receiver.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Foundation
2-
import SwiftProtobuf
32
import os
3+
import SwiftProtobuf
44

55
/// An actor that reads data from a `DispatchIO` channel, and deserializes it into VPN protocol messages.
66
actor Receiver<RecvMsg: Message> {
@@ -19,7 +19,7 @@ actor Receiver<RecvMsg: Message> {
1919
private func readLen() async throws -> UInt32 {
2020
let lenD: Data = try await withCheckedThrowingContinuation { continuation in
2121
var lenData = Data()
22-
dispatch.read(offset: 0, length: 4, queue: queue) {done, data, error in
22+
dispatch.read(offset: 0, length: 4, queue: queue) { done, data, error in
2323
guard error == 0 else {
2424
let errStrPtr = strerror(error)
2525
let errStr = String(validatingUTF8: errStrPtr!)!
@@ -39,7 +39,7 @@ actor Receiver<RecvMsg: Message> {
3939
private func readMsg(_ length: UInt32) async throws -> RecvMsg {
4040
let msgData: Data = try await withCheckedThrowingContinuation { continuation in
4141
var msgData = Data()
42-
dispatch.read(offset: 0, length: Int(length), queue: queue) {done, data, error in
42+
dispatch.read(offset: 0, length: Int(length), queue: queue) { done, data, error in
4343
guard error == 0 else {
4444
let errStrPtr = strerror(error)
4545
let errStr = String(validatingUTF8: errStrPtr!)!

‎Coder Desktop/Proto/Speaker.swift

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import Foundation
2-
import SwiftProtobuf
32
import os
3+
import SwiftProtobuf
44

5-
let newLine = 0x0a
5+
let newLine = 0x0A
66
let headerPreamble = "codervpn"
77

88
/// A message that has the `rpc` property for recording participation in a unary RPC.
99
protocol RPCMessage {
10-
var rpc: Vpn_RPC {get set}
10+
var rpc: Vpn_RPC { get set }
1111
/// Returns true if `rpc` has been explicitly set.
12-
var hasRpc: Bool {get}
12+
var hasRpc: Bool { get }
1313
}
1414

1515
extension Vpn_TunnelMessage: RPCMessage {}
@@ -26,15 +26,15 @@ struct ProtoVersion: CustomStringConvertible, Equatable, Codable {
2626
let major: Int
2727
let minor: Int
2828

29-
var description: String {"\(major).\(minor)"}
29+
var description: String { "\(major).\(minor)" }
3030

3131
init(_ major: Int, _ minor: Int) {
3232
self.major = major
3333
self.minor = minor
3434
}
3535

3636
init(parse str: String) throws {
37-
let parts = str.split(separator: ".").map({Int($0)})
37+
let parts = str.split(separator: ".").map { Int($0) }
3838
if parts.count != 2 {
3939
throw HandshakeError.invalidVersion(str)
4040
}
@@ -65,23 +65,24 @@ class Speaker<SendMsg: RPCMessage & Message, RecvMsg: RPCMessage & Message> {
6565
init(writeFD: FileHandle, readFD: FileHandle) {
6666
self.writeFD = writeFD
6767
self.readFD = readFD
68-
self.sender = Sender(writeFD: writeFD)
69-
self.dispatch = DispatchIO(
68+
sender = Sender(writeFD: writeFD)
69+
dispatch = DispatchIO(
7070
type: .stream,
7171
fileDescriptor: readFD.fileDescriptor,
7272
queue: queue,
73-
cleanupHandler: {_ in
74-
do {
75-
try readFD.close()
76-
} catch {
77-
// TODO
73+
cleanupHandler: { _ in
74+
do {
75+
try readFD.close()
76+
} catch {
77+
// TODO:
78+
}
7879
}
79-
})
80-
self.receiver = Receiver(dispatch: self.dispatch, queue: self.queue)
80+
)
81+
receiver = Receiver(dispatch: dispatch, queue: queue)
8182
if SendMsg.self == Vpn_TunnelMessage.self {
82-
self.role = .tunnel
83+
role = .tunnel
8384
} else {
84-
self.role = .manager
85+
role = .manager
8586
}
8687
}
8788

@@ -94,22 +95,22 @@ class Speaker<SendMsg: RPCMessage & Message, RecvMsg: RPCMessage & Message> {
9495

9596
/// Reads and handles protocol messages.
9697
func readLoop() async throws {
97-
for try await msg in try await self.receiver.messages() {
98+
for try await msg in try await receiver.messages() {
9899
guard msg.hasRpc else {
99-
self.handleMessage(msg)
100+
handleMessage(msg)
100101
continue
101102
}
102103
guard msg.rpc.msgID == 0 else {
103-
let req = RPCRequest<SendMsg, RecvMsg>(req: msg, sender: self.sender)
104-
self.handleRPC(req)
104+
let req = RPCRequest<SendMsg, RecvMsg>(req: msg, sender: sender)
105+
handleRPC(req)
105106
continue
106107
}
107108
guard msg.rpc.responseTo == 0 else {
108-
self.logger.debug("got RPC reply for msgID \(msg.rpc.responseTo)")
109+
logger.debug("got RPC reply for msgID \(msg.rpc.responseTo)")
109110
do throws(RPCError) {
110111
try await self.secretary.route(reply: msg)
111112
} catch {
112-
self.logger.error(
113+
logger.error(
113114
"couldn't route RPC reply for \(msg.rpc.responseTo): \(error)")
114115
}
115116
continue
@@ -120,13 +121,13 @@ class Speaker<SendMsg: RPCMessage & Message, RecvMsg: RPCMessage & Message> {
120121
/// Handles a single non-RPC message. It is expected that subclasses override this method with their own handlers.
121122
func handleMessage(_ msg: RecvMsg) {
122123
// just log
123-
self.logger.debug("got non-RPC message \(msg.textFormatString())")
124+
logger.debug("got non-RPC message \(msg.textFormatString())")
124125
}
125126

126127
/// Handle a single RPC request. It is expected that subclasses override this method with their own handlers.
127128
func handleRPC(_ req: RPCRequest<SendMsg, RecvMsg>) {
128129
// just log
129-
self.logger.debug("got RPC message \(req.msg.textFormatString())")
130+
logger.debug("got RPC message \(req.msg.textFormatString())")
130131
}
131132

132133
/// Send a unary RPC message and handle the response
@@ -152,15 +153,15 @@ class Speaker<SendMsg: RPCMessage & Message, RecvMsg: RPCMessage & Message> {
152153

153154
func closeWrite() {
154155
do {
155-
try self.writeFD.close()
156+
try writeFD.close()
156157
} catch {
157158
logger.error("failed to close write file handle: \(error)")
158159
}
159160
}
160161

161162
func closeRead() {
162163
do {
163-
try self.readFD.close()
164+
try readFD.close()
164165
} catch {
165166
logger.error("failed to close read file handle: \(error)")
166167
}
@@ -171,16 +172,16 @@ class Speaker<SendMsg: RPCMessage & Message, RecvMsg: RPCMessage & Message> {
171172
class Handshaker {
172173
private let writeFD: FileHandle
173174
private let dispatch: DispatchIO
174-
private var theirData: Data = Data()
175+
private var theirData: Data = .init()
175176
private let versions: [ProtoVersion]
176177
private let role: ProtoRole
177178
private var continuation: CheckedContinuation<Data, any Error>?
178179
private let queue: DispatchQueue
179180

180-
init (writeFD: FileHandle, dispatch: DispatchIO, queue: DispatchQueue,
181-
role: ProtoRole,
182-
versions: [ProtoVersion] = [.init(1, 0)]
183-
) {
181+
init(writeFD: FileHandle, dispatch: DispatchIO, queue: DispatchQueue,
182+
role: ProtoRole,
183+
versions: [ProtoVersion] = [.init(1, 0)])
184+
{
184185
self.writeFD = writeFD
185186
self.dispatch = dispatch
186187
self.role = role
@@ -198,7 +199,7 @@ class Handshaker {
198199
handleRead(false, nil, 0)
199200
}
200201

201-
let vStr = versions.map({$0.description}).joined(separator: ",")
202+
let vStr = versions.map { $0.description }.joined(separator: ",")
202203
let ours = String(format: "\(headerPreamble) \(role) \(vStr)\n")
203204
try writeFD.write(contentsOf: ours.data(using: .utf8)!)
204205

@@ -222,12 +223,12 @@ class Handshaker {
222223
continuation?.resume(throwing: HandshakeError.readError(errStr))
223224
return
224225
}
225-
if let ddd = data, !ddd.isEmpty {
226-
guard ddd[0] != newLine else {
226+
if let d = data, !d.isEmpty {
227+
guard d[0] != newLine else {
227228
continuation?.resume(returning: theirData)
228229
return
229230
}
230-
theirData.append(contentsOf: ddd)
231+
theirData.append(contentsOf: d)
231232
}
232233

233234
// read another byte, one at a time, so we don't read beyond the header.
@@ -243,15 +244,15 @@ class Handshaker {
243244
throw HandshakeError.invalidHeader("expected \(headerPreamble) but got \(parts[0])")
244245
}
245246
var expectedRole = ProtoRole.manager
246-
if self.role == .manager {
247+
if role == .manager {
247248
expectedRole = .tunnel
248249
}
249250
guard parts[1] == expectedRole.rawValue else {
250251
throw HandshakeError.wrongRole("expected \(expectedRole) but got \(parts[1])")
251252
}
252253
let theirVersions = try parts[2]
253254
.split(separator: ",")
254-
.map({try ProtoVersion(parse: String($0))})
255+
.map { try ProtoVersion(parse: String($0)) }
255256
return try pickVersion(ours: versions, theirs: theirVersions)
256257
}
257258
}
@@ -281,7 +282,7 @@ struct RPCRequest<SendMsg: RPCMessage & Message, RecvMsg: RPCMessage> {
281282
private let sender: Sender<SendMsg>
282283

283284
public init(req: RecvMsg, sender: Sender<SendMsg>) {
284-
self.msg = req
285+
msg = req
285286
self.sender = sender
286287
}
287288

‎Coder Desktop/ProtoTests/ProtoTests.swift

Lines changed: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
import Testing
2-
import Foundation
31
@testable import Coder_Desktop
2+
import Foundation
3+
import Testing
44

55
@Suite(.timeLimit(.minutes(1)))
66
struct SenderReceiverTests {
77
let pipe = Pipe()
88
let dispatch: DispatchIO
99
let queue: DispatchQueue = .global(qos: .utility)
10-
10+
1111
init() {
12-
self.dispatch = DispatchIO(
12+
dispatch = DispatchIO(
1313
type: .stream,
1414
fileDescriptor: pipe.fileHandleForReading.fileDescriptor,
1515
queue: queue,
16-
cleanupHandler: {error in print("cleanupHandler: \(error)")}
16+
cleanupHandler: { error in print("cleanupHandler: \(error)") }
1717
)
1818
}
1919

@@ -34,14 +34,14 @@ struct SenderReceiverTests {
3434
}
3535
#expect(count == 1)
3636
}
37-
37+
3838
@Test func sendMany() async throws {
3939
let s = Sender<Vpn_ManagerMessage>(writeFD: pipe.fileHandleForWriting)
4040
let r = Receiver<Vpn_ManagerMessage>(dispatch: dispatch, queue: queue)
4141
var msg = Vpn_ManagerMessage()
4242
msg.networkSettings.errorMessage = "test error"
4343
Task {
44-
for _ in 0..<10 {
44+
for _ in 0 ..< 10 {
4545
try await s.send(msg)
4646
}
4747
try await s.close()
@@ -62,28 +62,30 @@ struct HandshakerTests {
6262
let dispatchT: DispatchIO
6363
let dispatchM: DispatchIO
6464
let queue: DispatchQueue = .global(qos: .utility)
65-
65+
6666
init() {
67-
self.dispatchT = DispatchIO(
67+
dispatchT = DispatchIO(
6868
type: .stream,
6969
fileDescriptor: pipeMT.fileHandleForReading.fileDescriptor,
7070
queue: queue,
71-
cleanupHandler: {error in print("cleanupHandler: \(error)")}
71+
cleanupHandler: { error in print("cleanupHandler: \(error)") }
7272
)
73-
self.dispatchM = DispatchIO(
73+
dispatchM = DispatchIO(
7474
type: .stream,
7575
fileDescriptor: pipeTM.fileHandleForReading.fileDescriptor,
7676
queue: queue,
77-
cleanupHandler: {error in print("cleanupHandler: \(error)")}
77+
cleanupHandler: { error in print("cleanupHandler: \(error)") }
7878
)
7979
}
80-
80+
8181
@Test("Default versions")
8282
func mainline() async throws {
8383
let uutTun = Handshaker(
84-
writeFD: pipeTM.fileHandleForWriting, dispatch: dispatchT, queue: queue, role: .tunnel)
84+
writeFD: pipeTM.fileHandleForWriting, dispatch: dispatchT, queue: queue, role: .tunnel
85+
)
8586
let uutMgr = Handshaker(
86-
writeFD: pipeMT.fileHandleForWriting, dispatch: dispatchM, queue: queue, role: .manager)
87+
writeFD: pipeMT.fileHandleForWriting, dispatch: dispatchM, queue: queue, role: .manager
88+
)
8789
let taskTun = Task {
8890
try await uutTun.handshake()
8991
}
@@ -95,41 +97,45 @@ struct HandshakerTests {
9597
let versionMgr = try await taskMgr.value
9698
#expect(versionMgr == ProtoVersion(1, 0))
9799
}
98-
99-
100-
struct versionCase : CustomStringConvertible {
100+
101+
struct VersionCase: CustomStringConvertible {
101102
let tun: [ProtoVersion]
102103
let mgr: [ProtoVersion]
103104
let result: ProtoVersion
104-
105+
105106
var description: String {
106107
return "\(tun) vs \(mgr) -> \(result)"
107108
}
108109
}
109-
110+
110111
@Test("explicit versions", arguments: [
111-
versionCase(
112+
VersionCase(
112113
tun: [ProtoVersion(1, 0)],
113114
mgr: [ProtoVersion(1, 1)],
114-
result: ProtoVersion(1,0)),
115-
versionCase(
115+
result: ProtoVersion(1, 0)
116+
),
117+
VersionCase(
116118
tun: [ProtoVersion(1, 1)],
117119
mgr: [ProtoVersion(1, 7)],
118-
result: ProtoVersion(1,1)),
119-
versionCase(
120+
result: ProtoVersion(1, 1)
121+
),
122+
VersionCase(
120123
tun: [ProtoVersion(1, 7), ProtoVersion(2, 1)],
121124
mgr: [ProtoVersion(1, 7)],
122-
result: ProtoVersion(1, 7)),
123-
versionCase(
125+
result: ProtoVersion(1, 7)
126+
),
127+
VersionCase(
124128
tun: [ProtoVersion(1, 7)],
125129
mgr: [ProtoVersion(1, 7), ProtoVersion(2, 1)],
126-
result: ProtoVersion(1, 7)),
127-
versionCase(
130+
result: ProtoVersion(1, 7)
131+
),
132+
VersionCase(
128133
tun: [ProtoVersion(1, 3), ProtoVersion(2, 1)],
129134
mgr: [ProtoVersion(1, 7)],
130-
result: ProtoVersion(1, 3)),
135+
result: ProtoVersion(1, 3)
136+
),
131137
])
132-
func explictVersions(tc: versionCase) async throws {
138+
func explictVersions(tc: VersionCase) async throws {
133139
let uutTun = Handshaker(
134140
writeFD: pipeTM.fileHandleForWriting, dispatch: dispatchT, queue: queue, role: .tunnel,
135141
versions: tc.tun
@@ -149,16 +155,16 @@ struct HandshakerTests {
149155
let versionMgr = try await taskMgr.value
150156
#expect(versionMgr == tc.result)
151157
}
152-
158+
153159
@Test
154160
func incompatible() async throws {
155161
let uutTun = Handshaker(
156162
writeFD: pipeTM.fileHandleForWriting, dispatch: dispatchT, queue: queue, role: .tunnel,
157-
versions: [ProtoVersion(1,8)]
163+
versions: [ProtoVersion(1, 8)]
158164
)
159165
let uutMgr = Handshaker(
160166
writeFD: pipeMT.fileHandleForWriting, dispatch: dispatchM, queue: queue, role: .manager,
161-
versions: [ProtoVersion(2,8)]
167+
versions: [ProtoVersion(2, 8)]
162168
)
163169
let taskTun = Task {
164170
try await uutTun.handshake()
@@ -182,19 +188,19 @@ struct OneSidedHandshakerTests {
182188
let queue: DispatchQueue = .global(qos: .utility)
183189
let dispatchT: DispatchIO
184190
let uut: Handshaker
185-
191+
186192
init() {
187-
self.dispatchT = DispatchIO(
193+
dispatchT = DispatchIO(
188194
type: .stream,
189195
fileDescriptor: pipeMT.fileHandleForReading.fileDescriptor,
190196
queue: queue,
191-
cleanupHandler: {error in print("cleanupHandler: \(error)")}
197+
cleanupHandler: { error in print("cleanupHandler: \(error)") }
192198
)
193-
self.uut = Handshaker(
199+
uut = Handshaker(
194200
writeFD: pipeTM.fileHandleForWriting, dispatch: dispatchT, queue: queue, role: .tunnel
195201
)
196202
}
197-
203+
198204
@Test()
199205
func badPreamble() async throws {
200206
let taskTun = Task {
@@ -207,7 +213,7 @@ struct OneSidedHandshakerTests {
207213
try await taskTun.value
208214
}
209215
}
210-
216+
211217
@Test(.timeLimit(.minutes(1)))
212218
func badRole() async throws {
213219
let taskTun = Task {
@@ -220,7 +226,7 @@ struct OneSidedHandshakerTests {
220226
try await taskTun.value
221227
}
222228
}
223-
229+
224230
@Test(.timeLimit(.minutes(1)))
225231
func badVersion() async throws {
226232
let taskTun = Task {
@@ -233,7 +239,7 @@ struct OneSidedHandshakerTests {
233239
try await taskTun.value
234240
}
235241
}
236-
242+
237243
@Test(.timeLimit(.minutes(1)))
238244
func mainline() async throws {
239245
let taskTun = Task {
@@ -245,9 +251,8 @@ struct OneSidedHandshakerTests {
245251
pipeMT.fileHandleForWriting.write(Data("codervpn manager 1.0\n".utf8))
246252
let tunHdr = try pipeTM.fileHandleForReading.readToEnd()
247253
#expect(tunHdr == Data("codervpn tunnel 1.0\n".utf8))
248-
254+
249255
let v = try await taskTun.value
250-
#expect(v == ProtoVersion(1,0))
256+
#expect(v == ProtoVersion(1, 0))
251257
}
252258
}
253-

‎Coder Desktop/ProtoTests/SpeakerTests.swift

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import Testing
2-
import Foundation
31
@testable import Coder_Desktop
2+
import Foundation
3+
import Testing
44

55
/// A concrete, test class for the abstract Speaker, which overrides the handlers to send things to
66
/// continuations we set in the test.
@@ -9,7 +9,7 @@ class TestTunnel: Speaker<Vpn_TunnelMessage, Vpn_ManagerMessage> {
99
override func handleMessage(_ msg: Vpn_ManagerMessage) {
1010
msgHandler?.resume(returning: msg)
1111
}
12-
12+
1313
var rpcHandler: CheckedContinuation<RPCRequest<Vpn_TunnelMessage, Vpn_ManagerMessage>, Error>?
1414
override func handleRPC(_ req: RPCRequest<Vpn_TunnelMessage, Vpn_ManagerMessage>) {
1515
rpcHandler?.resume(returning: req)
@@ -25,36 +25,37 @@ struct SpeakerTests {
2525
let dispatch: DispatchIO
2626
let receiver: Receiver<Vpn_TunnelMessage>
2727
let handshaker: Handshaker
28-
28+
2929
init() {
3030
let queue = DispatchQueue.global(qos: .utility)
31-
self.uut = TestTunnel(
31+
uut = TestTunnel(
3232
writeFD: pipeTM.fileHandleForWriting,
3333
readFD: pipeMT.fileHandleForReading
3434
)
35-
self.dispatch = DispatchIO(
35+
dispatch = DispatchIO(
3636
type: .stream,
3737
fileDescriptor: pipeTM.fileHandleForReading.fileDescriptor,
3838
queue: queue,
39-
cleanupHandler: {error in print("cleanupHandler: \(error)")}
39+
cleanupHandler: { error in print("cleanupHandler: \(error)") }
4040
)
41-
self.sender = Sender(writeFD: pipeMT.fileHandleForWriting)
42-
self.receiver = Receiver(dispatch: dispatch, queue: queue)
43-
self.handshaker = Handshaker(
41+
sender = Sender(writeFD: pipeMT.fileHandleForWriting)
42+
receiver = Receiver(dispatch: dispatch, queue: queue)
43+
handshaker = Handshaker(
4444
writeFD: pipeMT.fileHandleForWriting,
45-
dispatch: self.dispatch, queue: queue,
46-
role: .manager)
45+
dispatch: dispatch, queue: queue,
46+
role: .manager
47+
)
4748
}
48-
49+
4950
@Test func handshake() async throws {
5051
async let v = handshaker.handshake()
5152
try await uut.handshake()
5253
#expect(try await v == ProtoVersion(1, 0))
5354
}
54-
55+
5556
@Test func handleSingleMessage() async throws {
5657
async let readDone: () = try uut.readLoop()
57-
58+
5859
let got = try await withCheckedThrowingContinuation { continuation in
5960
uut.msgHandler = continuation
6061
Task {
@@ -69,10 +70,10 @@ struct SpeakerTests {
6970
try await sender.close()
7071
try await readDone
7172
}
72-
73+
7374
@Test func handleRPC() async throws {
7475
async let readDone: () = try uut.readLoop()
75-
76+
7677
let got = try await withCheckedThrowingContinuation { continuation in
7778
uut.rpcHandler = continuation
7879
Task {
@@ -92,7 +93,7 @@ struct SpeakerTests {
9293
reply.rpc.responseTo = 33
9394
try await got.sendReply(reply)
9495
uut.closeWrite()
95-
96+
9697
var count = 0
9798
await #expect(throws: Never.self) {
9899
for try await reply in try await receiver.messages() {
@@ -104,11 +105,11 @@ struct SpeakerTests {
104105
try await sender.close()
105106
try await readDone
106107
}
107-
108+
108109
@Test func sendRPCs() async throws {
109110
async let readDone: () = try uut.readLoop()
110-
111-
async let managerDone = Task {
111+
112+
async let managerDone = Task {
112113
var count = 0
113114
for try await req in try await receiver.messages() {
114115
#expect(req.msg == .networkSettings(Vpn_NetworkSettingsRequest()))
@@ -122,7 +123,7 @@ struct SpeakerTests {
122123
}
123124
#expect(count == 2)
124125
}
125-
for i in 0..<2 {
126+
for i in 0 ..< 2 {
126127
var req = Vpn_TunnelMessage()
127128
req.networkSettings = Vpn_NetworkSettingsRequest()
128129
let got = try await uut.unaryRPC(req)

‎Coder Desktop/VPN/PacketTunnelProvider.swift

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,27 @@
11
import NetworkExtension
22

33
class PacketTunnelProvider: NEPacketTunnelProvider {
4-
5-
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
4+
override func startTunnel(options _: [String: NSObject]?, completionHandler _: @escaping (Error?) -> Void) {
65
// Add code here to start the process of connecting the tunnel.
76
}
8-
9-
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
7+
8+
override func stopTunnel(with _: NEProviderStopReason, completionHandler: @escaping () -> Void) {
109
// Add code here to start the process of stopping the tunnel.
1110
completionHandler()
1211
}
13-
12+
1413
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
1514
// Add code here to handle the message.
1615
if let handler = completionHandler {
1716
handler(messageData)
1817
}
1918
}
20-
19+
2120
override func sleep(completionHandler: @escaping () -> Void) {
2221
// Add code here to get ready to sleep.
2322
completionHandler()
2423
}
25-
24+
2625
override func wake() {
2726
// Add code here to wake up.
2827
}

‎Makefile

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,37 @@
1+
ifdef CI
2+
LINTFLAGS := --reporter github-actions-logging
3+
FMTFLAGS := --lint --reporter github-actions-log
4+
else
5+
LINTFLAGS :=
6+
FMTFLAGS :=
7+
endif
8+
9+
PROJECT := "Coder Desktop/Coder Desktop.xcodeproj"
10+
SCHEME := "Coder Desktop"
11+
12+
fmt:
13+
swiftformat \
14+
--exclude '**.pb.swift' \
15+
$(FMTFLAGS) .
16+
17+
test:
18+
xcodebuild test \
19+
-project $(PROJECT) \
20+
-scheme $(SCHEME) \
21+
-testPlan $(SCHEME) \
22+
-skipPackagePluginValidation \
23+
CODE_SIGNING_REQUIRED=NO \
24+
CODE_SIGNING_ALLOWED=NO \
25+
| LC_ALL="en_US.UTF-8" xcpretty
26+
27+
lint:
28+
swiftlint \
29+
--strict \
30+
--quiet $(LINTFLAGS)
31+
32+
clean:
33+
xcodebuild clean \
34+
-project $(PROJECT)
35+
136
proto:
237
protoc --swift_out=. 'Coder Desktop/Proto/vpn.proto'

0 commit comments

Comments
 (0)
Please sign in to comment.