crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

XDMarkupTests.swift (3386B)


      1 import Foundation
      2 import Testing
      3 
      4 @testable import Crossmate
      5 
      6 @Suite("XDMarkup")
      7 struct XDMarkupTests {
      8 
      9     private struct Run: Equatable {
     10         let text: String
     11         let intent: InlinePresentationIntent?
     12     }
     13 
     14     /// The styled substrings of an attributed string, paired with the emphasis
     15     /// intent applied to each, matching `AttributedString.runs`.
     16     private func runs(_ attributed: AttributedString) -> [Run] {
     17         attributed.runs.map { run in
     18             Run(text: String(attributed[run.range].characters), intent: run.inlinePresentationIntent)
     19         }
     20     }
     21 
     22     @Test("Plain clue text round-trips with no emphasis")
     23     func plainTextHasNoEmphasis() {
     24         let attributed = XDMarkup.attributed("Capital of France")
     25         #expect(runs(attributed) == [Run(text: "Capital of France", intent: nil)])
     26         #expect(XDMarkup.stripped("Capital of France") == "Capital of France")
     27     }
     28 
     29     @Test("Italic span renders emphasized and strips its braces")
     30     func italicSpan() {
     31         let source = "{/Why Keanu is such a generous tipper?/}"
     32         let attributed = XDMarkup.attributed(source)
     33         #expect(runs(attributed) == [Run(text: "Why Keanu is such a generous tipper?", intent: .emphasized)])
     34         #expect(XDMarkup.stripped(source) == "Why Keanu is such a generous tipper?")
     35     }
     36 
     37     @Test("Mid-clue italics leave surrounding text plain")
     38     func partialItalics() {
     39         let attributed = XDMarkup.attributed("As seen in {/Hamlet/}, e.g.")
     40         #expect(runs(attributed) == [
     41             Run(text: "As seen in ", intent: nil),
     42             Run(text: "Hamlet", intent: .emphasized),
     43             Run(text: ", e.g.", intent: nil)
     44         ])
     45     }
     46 
     47     @Test("Bold maps to strong emphasis")
     48     func boldSpan() {
     49         let attributed = XDMarkup.attributed("{*Note*}: read carefully")
     50         #expect(runs(attributed) == [
     51             Run(text: "Note", intent: .stronglyEmphasized),
     52             Run(text: ": read carefully", intent: nil)
     53         ])
     54     }
     55 
     56     @Test("Strikethrough span carries the strikethrough intent")
     57     func strikethroughSpan() {
     58         let attributed = XDMarkup.attributed("{-gone-}")
     59         #expect(runs(attributed) == [Run(text: "gone", intent: .strikethrough)])
     60     }
     61 
     62     @Test("Strikethrough delimiter only closes at a brace, not an internal hyphen")
     63     func strikethroughWithInternalHyphen() {
     64         #expect(XDMarkup.stripped("{-strike-thru-}") == "strike-thru")
     65     }
     66 
     67     @Test("A literal asterisk in plain prose is left untouched")
     68     func literalAsteriskUntouched() {
     69         // Starred theme clues carry a bare '*' that must not be read as markup.
     70         let source = "*Sphere of influence"
     71         #expect(runs(XDMarkup.attributed(source)) == [Run(text: source, intent: nil)])
     72         #expect(XDMarkup.stripped(source) == source)
     73     }
     74 
     75     @Test("An unterminated span stays literal")
     76     func unterminatedSpanStaysLiteral() {
     77         let source = "Set in {/the past"
     78         #expect(runs(XDMarkup.attributed(source)) == [Run(text: source, intent: nil)])
     79         #expect(XDMarkup.stripped(source) == source)
     80     }
     81 
     82     @Test("A brace with no valid marker stays literal")
     83     func braceWithoutMarkerStaysLiteral() {
     84         let source = "Score of {0}"
     85         #expect(runs(XDMarkup.attributed(source)) == [Run(text: source, intent: nil)])
     86         #expect(XDMarkup.stripped(source) == source)
     87     }
     88 }