Complete native rewrite of the web-based SoliCards game as a SwiftUI multiplatform app targeting iOS 17+, iPadOS 17+, and macOS 14+. Three solitaire variants (Klondike, Spider, FreeCell) with full game rules, drag & drop, smart zoom layout, 6 themes, 4 difficulty levels, SwiftData persistence, VoiceOver accessibility, and 57 unit tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
134 lines
3.5 KiB
Swift
134 lines
3.5 KiB
Swift
import Testing
|
|
@testable import SoliCards
|
|
|
|
@Suite("Difficulty Tests")
|
|
struct DifficultyTests {
|
|
|
|
@Test("Easy settings")
|
|
func easySettings() {
|
|
let settings = Difficulty.easy.settings
|
|
#expect(settings.drawCount == 1)
|
|
#expect(settings.maxUndos == .max)
|
|
#expect(settings.hintsEnabled)
|
|
#expect(settings.scoreMultiplier == 0.5)
|
|
}
|
|
|
|
@Test("Medium settings")
|
|
func mediumSettings() {
|
|
let settings = Difficulty.medium.settings
|
|
#expect(settings.drawCount == 3)
|
|
#expect(settings.maxUndos == 20)
|
|
#expect(settings.hintsEnabled)
|
|
}
|
|
|
|
@Test("Hard settings disable hints")
|
|
func hardNoHints() {
|
|
let settings = Difficulty.hard.settings
|
|
#expect(!settings.hintsEnabled)
|
|
#expect(settings.maxUndos == 10)
|
|
}
|
|
|
|
@Test("Expert settings are most restrictive")
|
|
func expertSettings() {
|
|
let settings = Difficulty.expert.settings
|
|
#expect(!settings.hintsEnabled)
|
|
#expect(settings.maxUndos == 5)
|
|
#expect(settings.scoreMultiplier == 2.0)
|
|
}
|
|
|
|
@Test("All difficulties have display names")
|
|
func displayNames() {
|
|
for difficulty in Difficulty.allCases {
|
|
#expect(!difficulty.displayName.isEmpty)
|
|
}
|
|
}
|
|
}
|
|
|
|
@Suite("GameVariant Tests")
|
|
struct GameVariantTests {
|
|
|
|
@Test("Klondike properties")
|
|
func klondikeProps() {
|
|
let v = GameVariant.klondike
|
|
#expect(v.tableauCount == 7)
|
|
#expect(v.foundationCount == 4)
|
|
#expect(v.deckCount == 1)
|
|
#expect(v.hasWaste)
|
|
#expect(v.hasStock)
|
|
#expect(!v.hasFreeCells)
|
|
}
|
|
|
|
@Test("Spider properties")
|
|
func spiderProps() {
|
|
let v = GameVariant.spider
|
|
#expect(v.tableauCount == 10)
|
|
#expect(v.foundationCount == 8)
|
|
#expect(v.deckCount == 2)
|
|
#expect(!v.hasFreeCells)
|
|
}
|
|
|
|
@Test("FreeCell properties")
|
|
func freeCellProps() {
|
|
let v = GameVariant.freeCell
|
|
#expect(v.tableauCount == 8)
|
|
#expect(v.foundationCount == 4)
|
|
#expect(v.deckCount == 1)
|
|
#expect(!v.hasWaste)
|
|
#expect(!v.hasStock)
|
|
#expect(v.hasFreeCells)
|
|
#expect(v.freeCellCount == 4)
|
|
}
|
|
}
|
|
|
|
@Suite("Rank Tests")
|
|
struct RankTests {
|
|
|
|
@Test("Rank ordering")
|
|
func rankOrder() {
|
|
#expect(Rank.ace < Rank.two)
|
|
#expect(Rank.queen < Rank.king)
|
|
#expect(Rank.ace.rawValue == 1)
|
|
#expect(Rank.king.rawValue == 13)
|
|
}
|
|
|
|
@Test("All 13 ranks exist")
|
|
func allRanks() {
|
|
#expect(Rank.allCases.count == 13)
|
|
}
|
|
|
|
@Test("File names for assets")
|
|
func fileNames() {
|
|
#expect(Rank.ace.fileName == "ace")
|
|
#expect(Rank.two.fileName == "2")
|
|
#expect(Rank.ten.fileName == "10")
|
|
#expect(Rank.jack.fileName == "jack")
|
|
#expect(Rank.queen.fileName == "queen")
|
|
#expect(Rank.king.fileName == "king")
|
|
}
|
|
}
|
|
|
|
@Suite("Suit Tests")
|
|
struct SuitTests {
|
|
|
|
@Test("Red and black suits")
|
|
func suitColors() {
|
|
#expect(Suit.hearts.color == .red)
|
|
#expect(Suit.diamonds.color == .red)
|
|
#expect(Suit.spades.color == .black)
|
|
#expect(Suit.clubs.color == .black)
|
|
}
|
|
|
|
@Test("All 4 suits exist")
|
|
func allSuits() {
|
|
#expect(Suit.allCases.count == 4)
|
|
}
|
|
|
|
@Test("Suit symbols")
|
|
func symbols() {
|
|
#expect(Suit.spades.symbol == "♠")
|
|
#expect(Suit.hearts.symbol == "♥")
|
|
#expect(Suit.diamonds.symbol == "♦")
|
|
#expect(Suit.clubs.symbol == "♣")
|
|
}
|
|
}
|