import Foundation import Testing @testable import Persistence @Suite( "Sale model", .tags(.model) ) struct SaleTests { // MARK: Computed tests @Test func `walks the handshake one step at a time`() { #expect(sale().completed == .agreed) #expect(sale().next == .paid) #expect(sale(paid: true).completed == .paid) #expect(sale(paid: true, sent: true).completed == .sent) #expect(sale(paid: true, sent: true, received: true).completed == .received) #expect(sale(paid: true, sent: true, received: true, buyerRating: 5).completed == .received) #expect(sale(paid: true, sent: true, received: true, buyerRating: 5, sellerRating: 4).completed == .rated) #expect(sale(paid: true, sent: true, received: true, buyerRating: 5, sellerRating: 4).next == nil) } @Test func `adds the shipping to the price`() { #expect(sale().totalCents == 22_100) } // MARK: Methods tests @Test func `gives each step to its party, once, in order`() { #expect(sale().allows(.markPaid(note: ""), by: .buyer)) #expect(!sale().allows(.markPaid(note: ""), by: .seller)) #expect(!sale(paid: true).allows(.markPaid(note: ""), by: .buyer)) #expect(!sale().allows(.markSent(note: ""), by: .seller)) #expect(sale(paid: true).allows(.markSent(note: ""), by: .seller)) #expect(!sale(paid: true).allows(.markSent(note: ""), by: .buyer)) #expect(!sale(paid: true).allows(.markReceived, by: .buyer)) #expect(sale(paid: true, sent: true).allows(.markReceived, by: .buyer)) #expect(!sale(paid: true, sent: true).allows(.markReceived, by: .seller)) } @Test func `unlocks ratings only once the copy is received, one per party, out of five`() { let received = sale(paid: true, sent: true, received: true) #expect(!sale(paid: true, sent: true).allows(.rate(stars: 5), by: .buyer)) #expect(received.allows(.rate(stars: 5), by: .buyer)) #expect(received.allows(.rate(stars: 1), by: .seller)) #expect(!received.allows(.rate(stars: 0), by: .buyer)) #expect(!received.allows(.rate(stars: 6), by: .buyer)) #expect(!sale(paid: true, sent: true, received: true, buyerRating: 5).allows(.rate(stars: 4), by: .buyer)) #expect(sale(paid: true, sent: true, received: true, buyerRating: 5).allows(.rate(stars: 4), by: .seller)) } @Test func `knows its parties`() { let sale = sale() #expect(sale.role(of: sale.buyer.id) == .buyer) #expect(sale.role(of: sale.seller.id) == .seller) #expect(sale.role(of: .init()) == nil) } // MARK: Offer tests @Test(arguments: zip( [24_000, 1_400, 4_500, 100], [19_200, 1_200, 3_600, 100] )) func `floors offers at four fifths of the asking price, in whole euros`( asking: Int, expects floor: Int ) { #expect(Offer.floor(forAsking: asking) == floor) } } // MARK: - Helpers private extension SaleTests { /// A sale of the first demo listing at €215 + €6, as far along as told. func sale( paid: Bool = false, sent: Bool = false, received: Bool = false, buyerRating: Int? = nil, sellerRating: Int? = nil ) -> Sale { let stamp = Date(timeIntervalSince1970: 0) return .init( number: 48_213, conversationID: .init(), listing: Seed.listings[0], buyer: .init(id: .init(), email: "mara.v@example.com", displayName: "Mara Visser"), seller: .init(id: .init(), email: "joost@kestrelrow.example", displayName: "Joost de Wit"), priceCents: 21_500, askedCents: 24_000, shippingCents: 600, declared: .init(grade: "CGC 9.8", pageQuality: "White", printing: "First printing", notes: ""), agreedAt: stamp, paidAt: paid ? stamp : nil, sentAt: sent ? stamp : nil, receivedAt: received ? stamp : nil, buyerRating: buyerRating, sellerRating: sellerRating ) } }