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>
82 lines
3.3 KiB
Swift
82 lines
3.3 KiB
Swift
import Testing
|
|
@testable import SoliCards
|
|
|
|
@Suite("MoveValidator Tests")
|
|
struct MoveValidatorTests {
|
|
|
|
@Test("Alternating color detection")
|
|
func alternatingColor() {
|
|
let redCard = Card(suit: .hearts, rank: .five, isFaceUp: true)
|
|
let blackCard = Card(suit: .spades, rank: .four, isFaceUp: true)
|
|
let anotherRed = Card(suit: .diamonds, rank: .three, isFaceUp: true)
|
|
|
|
#expect(MoveValidator.isAlternatingColor(redCard, with: blackCard))
|
|
#expect(MoveValidator.isAlternatingColor(blackCard, with: redCard))
|
|
#expect(!MoveValidator.isAlternatingColor(redCard, with: anotherRed))
|
|
}
|
|
|
|
@Test("Same suit detection")
|
|
func sameSuit() {
|
|
let spade1 = Card(suit: .spades, rank: .ace, isFaceUp: true)
|
|
let spade2 = Card(suit: .spades, rank: .king, isFaceUp: true)
|
|
let heart = Card(suit: .hearts, rank: .ace, isFaceUp: true)
|
|
|
|
#expect(MoveValidator.isSameSuit(spade1, as: spade2))
|
|
#expect(!MoveValidator.isSameSuit(spade1, as: heart))
|
|
}
|
|
|
|
@Test("Ascending rank (for foundations)")
|
|
func ascending() {
|
|
let ace = Card(suit: .hearts, rank: .ace, isFaceUp: true)
|
|
let two = Card(suit: .hearts, rank: .two, isFaceUp: true)
|
|
let three = Card(suit: .hearts, rank: .three, isFaceUp: true)
|
|
|
|
#expect(MoveValidator.isAscending(two, onto: ace))
|
|
#expect(MoveValidator.isAscending(three, onto: two))
|
|
#expect(!MoveValidator.isAscending(three, onto: ace))
|
|
#expect(!MoveValidator.isAscending(ace, onto: two))
|
|
}
|
|
|
|
@Test("Descending rank (for tableaus)")
|
|
func descending() {
|
|
let king = Card(suit: .spades, rank: .king, isFaceUp: true)
|
|
let queen = Card(suit: .hearts, rank: .queen, isFaceUp: true)
|
|
let jack = Card(suit: .spades, rank: .jack, isFaceUp: true)
|
|
|
|
#expect(MoveValidator.isDescending(queen, onto: king))
|
|
#expect(MoveValidator.isDescending(jack, onto: queen))
|
|
#expect(!MoveValidator.isDescending(king, onto: queen))
|
|
}
|
|
|
|
@Test("Can place on foundation")
|
|
func canPlaceOnFoundation() {
|
|
let ace = Card(suit: .hearts, rank: .ace, isFaceUp: true)
|
|
let two = Card(suit: .hearts, rank: .two, isFaceUp: true)
|
|
let twoSpades = Card(suit: .spades, rank: .two, isFaceUp: true)
|
|
let three = Card(suit: .hearts, rank: .three, isFaceUp: true)
|
|
|
|
// Ace on empty foundation
|
|
#expect(MoveValidator.canPlaceOnFoundation(ace, topCard: nil))
|
|
// Non-ace on empty foundation
|
|
#expect(!MoveValidator.canPlaceOnFoundation(two, topCard: nil))
|
|
// Two of hearts on ace of hearts
|
|
#expect(MoveValidator.canPlaceOnFoundation(two, topCard: ace))
|
|
// Two of spades on ace of hearts (wrong suit)
|
|
#expect(!MoveValidator.canPlaceOnFoundation(twoSpades, topCard: ace))
|
|
// Three on ace (skipping)
|
|
#expect(!MoveValidator.canPlaceOnFoundation(three, topCard: ace))
|
|
}
|
|
|
|
@Test("Ace and King detection")
|
|
func aceAndKing() {
|
|
let ace = Card(suit: .clubs, rank: .ace)
|
|
let king = Card(suit: .clubs, rank: .king)
|
|
let five = Card(suit: .clubs, rank: .five)
|
|
|
|
#expect(MoveValidator.isAce(ace))
|
|
#expect(!MoveValidator.isAce(king))
|
|
#expect(MoveValidator.isKing(king))
|
|
#expect(!MoveValidator.isKing(five))
|
|
}
|
|
}
|