Skip to content

Commit 7949650

Browse files
authored
quickpass update, not complete (#18)
* quickpass update, not complete * applying default swift format * using isEmpty in test * using a marker class to identify the bundle and load it for the macOS executable location
1 parent cfaefbf commit 7949650

File tree

4 files changed

+160
-136
lines changed

4 files changed

+160
-136
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
/Packages
44
/*.xcodeproj
55
Package.resolved
6+
.swiftpm

Package.swift

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
// swift-tools-version:5.10
1+
// swift-tools-version:6.0
22

3-
/*
4-
This source file is part of the Swift.org open source project
5-
6-
Copyright 2015 – 2021 Apple Inc. and the Swift project authors
7-
Licensed under Apache License v2.0 with Runtime Library Exception
8-
9-
See http://swift.org/LICENSE.txt for license information
10-
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
11-
*/
3+
//===----------------------------------------------------------------------===//
4+
//
5+
// This source file is part of the example package dealer open source project
6+
//
7+
// Copyright (c) 2015-2025 Apple Inc. and the Swift project authors
8+
// Licensed under Apache License v2.0 with Runtime Library Exception
9+
//
10+
// See https://swift.org/LICENSE.txt for license information
11+
//
12+
//===----------------------------------------------------------------------===//
1213

1314
import PackageDescription
1415

@@ -27,7 +28,7 @@ let package = Package(
2728
from: "3.0.0"),
2829
.package(
2930
url: "https://github.com/apple/swift-argument-parser.git",
30-
from: "0.4.4"),
31+
from: "1.6.0"),
3132
],
3233
targets: [
3334
.executableTarget(

Sources/dealer/Dealer.swift

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,74 @@
1-
/*
2-
This source file is part of the Swift.org open source project
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the example package dealer open source project
4+
//
5+
// Copyright (c) 2015-2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
311

4-
Copyright 2015 – 2021 Apple Inc. and the Swift project authors
5-
Licensed under Apache License v2.0 with Runtime Library Exception
6-
7-
See http://swift.org/LICENSE.txt for license information
8-
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9-
*/
12+
import ArgumentParser
13+
import DeckOfPlayingCards
14+
import Foundation
15+
import PlayingCard
1016

1117
#if os(Linux)
12-
import Glibc
18+
import Glibc
1319
#endif
1420

15-
import Foundation
16-
import DeckOfPlayingCards
17-
import PlayingCard
18-
import ArgumentParser
19-
2021
@main
2122
struct Dealer: ParsableCommand {
22-
enum Error: Swift.Error, CustomStringConvertible {
23-
case notEnoughCards
23+
enum Error: Swift.Error, CustomStringConvertible {
24+
case notEnoughCards
2425

25-
var description: String {
26-
switch self {
27-
case .notEnoughCards:
28-
return "Not enough cards"
29-
}
30-
}
26+
var description: String {
27+
switch self {
28+
case .notEnoughCards:
29+
return "Not enough cards"
30+
}
3131
}
32+
}
3233

33-
static var configuration = CommandConfiguration(
34-
abstract: "Shuffles a deck of playing cards and deals a number of cards.",
35-
discussion: """
36-
For each count argument, prints a line of tab-delimited cards to stdout,
37-
or if there aren't enough cards remaining,
38-
prints "Not enough cards" to stderr and exits with a nonzero status.
39-
""")
34+
static let configuration = CommandConfiguration(
35+
abstract: "Shuffles a deck of playing cards and deals a number of cards.",
36+
discussion: """
37+
For each count argument, prints a line of tab-delimited cards to stdout,
38+
or if there aren't enough cards remaining,
39+
prints "Not enough cards" to stderr and exits with a nonzero status.
40+
""")
4041

41-
@Argument(help: .init("The number of cards to deal at a time.",
42-
valueName: "count"))
43-
var counts: [UInt]
42+
@Argument(
43+
help: .init(
44+
"The number of cards to deal at a time.",
45+
valueName: "count"))
46+
var counts: [UInt]
4447

45-
mutating func run() throws {
46-
#if os(Linux)
47-
srandom(UInt32(clock()))
48-
#endif
48+
mutating func run() throws {
49+
#if os(Linux)
50+
srandom(UInt32(clock()))
51+
#endif
4952

50-
var deck = Deck.standard52CardDeck()
51-
deck.shuffle()
53+
var deck = Deck.standard52CardDeck()
54+
deck.shuffle()
5255

53-
for count in counts {
54-
var cards: [PlayingCard] = []
56+
for count in counts {
57+
var cards: [PlayingCard] = []
5558

56-
for _ in 0..<count {
57-
guard let card = deck.deal() else {
58-
Self.exit(withError: Error.notEnoughCards)
59-
}
59+
for _ in 0..<count {
60+
guard let card = deck.deal() else {
61+
Self.exit(withError: Error.notEnoughCards)
62+
}
6063

61-
cards.append(card)
62-
}
64+
cards.append(card)
65+
}
6366

64-
print(cards.map(\.description).joined(separator: "\t"))
65-
}
67+
print(cards.map(\.description).joined(separator: "\t"))
6668
}
69+
}
6770
}
71+
72+
// Empty class that provides a convenient handle to request
73+
// the bundle that contains this code.
74+
class BundleMarker {}

Tests/DealerTests/DealerTests.swift

Lines changed: 92 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,118 @@
1-
/*
2-
This source file is part of the Swift.org open source project
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the example package dealer open source project
4+
//
5+
// Copyright (c) 2021-2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
import Foundation
13+
import Testing
314

4-
Copyright 2021 Apple Inc. and the Swift project authors
5-
Licensed under Apache License v2.0 with Runtime Library Exception
15+
import class Foundation.Bundle
616

7-
See http://swift.org/LICENSE.txt for license information
8-
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9-
*/
17+
@testable import dealer
1018

11-
import XCTest
12-
import class Foundation.Bundle
19+
struct DealerTests {
20+
@Test
21+
func testUsage() throws {
22+
let (status, output, error) = try execute(with: ["--help"])
23+
#expect(status == EXIT_SUCCESS)
24+
#expect(
25+
output?.starts(
26+
with: "OVERVIEW: Shuffles a deck of playing cards and deals a number of cards.") ?? false)
27+
#expect(error?.isEmpty == true)
28+
}
1329

14-
final class DealerTests: XCTestCase {
15-
func testUsage() throws {
16-
let (status, output, error) = try execute(with: ["--help"])
17-
XCTAssertEqual(status, EXIT_SUCCESS)
18-
XCTAssert(output?.starts(with: "OVERVIEW: Shuffles a deck of playing cards and deals a number of cards.") ?? false)
19-
XCTAssertEqual(error, "")
20-
}
30+
@Test
31+
func testDealOneCard() throws {
32+
let (status, output, error) = try execute(with: ["1"])
33+
#expect(status == EXIT_SUCCESS)
34+
#expect(output?.filter(\.isPlayingCardSuit).count == 1)
2135

22-
func testDealOneCard() throws {
23-
let (status, output, error) = try execute(with: ["1"])
24-
XCTAssertEqual(status, EXIT_SUCCESS)
25-
XCTAssertEqual(output?.filter(\.isPlayingCardSuit).count, 1)
36+
#expect(error?.isEmpty == true)
2637

27-
XCTAssertEqual(error, "")
28-
}
38+
}
2939

30-
func testDealTenCards() throws {
31-
let (status, output, error) = try execute(with: ["10"])
32-
XCTAssertEqual(status, EXIT_SUCCESS)
33-
XCTAssertEqual(output?.filter(\.isPlayingCardSuit).count, 10)
40+
@Test
41+
func testDealTenCards() throws {
42+
let (status, output, error) = try execute(with: ["10"])
43+
#expect(status == EXIT_SUCCESS)
44+
#expect(output?.filter(\.isPlayingCardSuit).count == 10)
3445

35-
XCTAssertEqual(error, "")
36-
}
46+
#expect(error?.isEmpty == true)
3747

38-
func testDealThirteenCardsFourTimes() throws {
39-
let (status, output, error) = try execute(with: ["13", "13", "13", "13"])
40-
XCTAssertEqual(status, EXIT_SUCCESS)
41-
XCTAssertEqual(output?.filter(\.isPlayingCardSuit).count, 52)
42-
XCTAssertEqual(output?.filter(\.isNewline).count, 4)
48+
}
4349

44-
XCTAssertEqual(error, "")
45-
}
50+
@Test
51+
func testDealThirteenCardsFourTimes() throws {
52+
let (status, output, error) = try execute(with: ["13", "13", "13", "13"])
53+
#expect(status == EXIT_SUCCESS)
54+
#expect(output?.filter(\.isPlayingCardSuit).count == 52)
55+
#expect(output?.filter(\.isNewline).count == 4)
4656

47-
func testDealOneHundredCards() throws {
48-
let (status, output, error) = try execute(with: ["100"])
49-
XCTAssertNotEqual(status, EXIT_SUCCESS)
50-
XCTAssertEqual(output, "")
51-
XCTAssertEqual(error, "Error: Not enough cards\n")
52-
}
57+
#expect(error?.isEmpty == true)
5358

54-
/// Returns path to the built products directory.
55-
var productsDirectory: URL {
56-
#if os(macOS)
57-
for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") {
58-
return bundle.bundleURL.deletingLastPathComponent()
59-
}
60-
fatalError("couldn't find the products directory")
61-
#else
62-
return Bundle.main.bundleURL
63-
#endif
64-
}
59+
}
6560

66-
private func execute(with arguments: [String] = []) throws -> (status: Int32, output: String?, error: String?) {
67-
let process = Process()
68-
process.executableURL = productsDirectory.appendingPathComponent("dealer")
69-
process.arguments = arguments
61+
@Test
62+
func testDealOneHundredCards() throws {
63+
let (status, output, error) = try execute(with: ["100"])
64+
#expect(status != EXIT_SUCCESS)
65+
#expect(output?.isEmpty == true)
7066

71-
let outputPipe = Pipe()
72-
process.standardOutput = outputPipe
67+
#expect(error == "Error: Not enough cards\n")
68+
}
7369

74-
let errorPipe = Pipe()
75-
process.standardError = errorPipe
70+
/// Returns path to the built products directory.
71+
var productsDirectory: URL {
72+
#if os(macOS)
73+
return Bundle(for: BundleMarker.self).bundleURL.deletingLastPathComponent()
74+
#else
75+
return Bundle.main.bundleURL
76+
#endif
77+
}
7678

77-
try process.run()
78-
process.waitUntilExit()
79+
private func execute(with arguments: [String] = []) throws -> (
80+
status: Int32, output: String?, error: String?
81+
) {
82+
let process = Process()
83+
process.executableURL = productsDirectory.appendingPathComponent("dealer")
84+
process.arguments = arguments
7985

80-
let status = process.terminationStatus
86+
let outputPipe = Pipe()
87+
process.standardOutput = outputPipe
8188

82-
let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
83-
let output = String(data: outputData, encoding: .utf8)
89+
let errorPipe = Pipe()
90+
process.standardError = errorPipe
8491

85-
let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()
86-
let error = String(data: errorData, encoding: .utf8)
92+
try process.run()
93+
process.waitUntilExit()
8794

88-
return (status, output, error)
89-
}
95+
let status = process.terminationStatus
96+
97+
let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
98+
let output = String(data: outputData, encoding: .utf8)
99+
100+
let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()
101+
let error = String(data: errorData, encoding: .utf8)
102+
103+
return (status, output, error)
104+
}
90105
}
91106

92107
// MARK: -
93108

94-
private extension Character {
95-
var isPlayingCardSuit: Bool {
96-
switch self {
97-
case "♠︎", "", "", "♣︎":
98-
return true
99-
default:
100-
return false
101-
}
109+
extension Character {
110+
fileprivate var isPlayingCardSuit: Bool {
111+
switch self {
112+
case "♠︎", "", "", "♣︎":
113+
return true
114+
default:
115+
return false
102116
}
117+
}
103118
}

0 commit comments

Comments
 (0)