krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Tests/OrgEditorAppKitTests/MarkupTests.swift

c1295824f55c7bba681fca8338bf08167e110105
orgstar/Tests/OrgEditorAppKitTests/MarkupTests.swift history · blame · raw

113 lines · 4426 bytes

  1import AppKit
  2import OrgCore
  3import OrgPresentation
  4import Testing
  5@testable import OrgEditorAppKit
  6
  7/// Hiding link and emphasis markup, with the caret's line showing it.
  8@MainActor
  9struct MarkupTests {
 10    static let text = "See [[https://example.org][Example]] and =code= here\nsecond line\n"
 11
 12    func size(_ h: Harness, at offset: Int) -> CGFloat {
 13        (h.textView.textStorage!.attribute(.font, at: offset, effectiveRange: nil) as! NSFont).pointSize
 14    }
 15
 16    func x(_ h: Harness, _ offset: Int) -> CGFloat {
 17        h.layout()
 18        return h.textView.firstRect(forCharacterRange: NSRange(location: offset, length: 1), actualRange: nil).minX
 19    }
 20
 21    @Test func hidesMarkupOffTheCaretLine() {
 22        let h = Harness(Self.text)
 23        let ns = Self.text as NSString
 24        let bracket = ns.range(of: "[[").location
 25        let equals = ns.range(of: "=code").location
 26        #expect(size(h, at: bracket) > 1)
 27
 28        h.caret(at: ns.range(of: "second").location)
 29        h.editor.options.hideEmphasisMarkers = true
 30        h.editor.showMarkup = false
 31        h.drainStyling()
 32        #expect(size(h, at: bracket) < 1)
 33        #expect(size(h, at: equals) < 1)
 34        #expect(size(h, at: ns.range(of: "Example").location) > 1)
 35        // Hidden text takes no room: "Example" starts right after "See ".
 36        let column = x(h, 1) - x(h, 0)
 37        #expect(abs(x(h, ns.range(of: "Example").location) - x(h, 0) - 4 * column) < 1)
 38
 39        h.caret(at: 1)
 40        #expect(size(h, at: bracket) > 1)
 41        h.caret(at: ns.range(of: "second").location)
 42        #expect(size(h, at: bracket) < 1)
 43
 44        h.editor.showMarkup = true
 45        h.drainStyling()
 46        #expect(size(h, at: bracket) > 1)
 47    }
 48
 49    @Test func emphasisFollowsTheEmacsSetting() {
 50        let h = Harness(Self.text)
 51        let ns = Self.text as NSString
 52        h.caret(at: ns.range(of: "second").location)
 53        h.editor.options.hideEmphasisMarkers = false
 54        h.editor.showMarkup = false
 55        h.drainStyling()
 56        #expect(size(h, at: ns.range(of: "=code").location) > 1)
 57        #expect(size(h, at: ns.range(of: "[[").location) < 1)
 58    }
 59}
 60
 61@MainActor
 62struct LineNumberTests {
 63    @Test func marginFollowsTheSettingAndLineCount() {
 64        let h = Harness("* a\nb\n")
 65        h.editor.showLineNumbers = true
 66        let narrow = h.textView.textContainerInset.width
 67        #expect(narrow > 0)
 68        h.textView.insertText(String(repeating: "x\n", count: 120), replacementRange: NSRange(location: 6, length: 0))
 69        #expect(h.textView.textContainerInset.width > narrow)
 70        h.editor.showLineNumbers = false
 71        #expect(h.textView.textContainerInset.width == 0)
 72    }
 73}
 74
 75@MainActor
 76struct PrettyEntityTests {
 77    @Test func entitiesShowAsCharactersOffTheCaretLine() {
 78        let text = "first\nThen \\alpha and x_{1}\n"
 79        let h = Harness(text)
 80        h.caret(at: 0)
 81        h.editor.options.prettyEntities = true
 82        h.editor.options.subSuperscriptsNeedBraces = true
 83        h.editor.showMarkup = false
 84        h.drainStyling()
 85        let storage = h.textView.textStorage!
 86        let last = (text as NSString).range(of: "\\alpha").location + 5
 87        #expect(storage.attribute(.orgEntityDisplay, at: last, effectiveRange: nil) as? String == "α")
 88        let one = (text as NSString).range(of: "1}").location
 89        #expect((storage.attribute(.baselineOffset, at: one, effectiveRange: nil) as? CGFloat ?? 0) < 0)
 90
 91        h.caret(at: last)
 92        #expect(storage.attribute(.orgEntityDisplay, at: last, effectiveRange: nil) == nil)
 93    }
 94}
 95
 96@MainActor
 97struct EditorThemeTests {
 98    @Test func themeChangesFontAndColors() {
 99        let h = Harness("* Heading\nbody\n")
100        var spec = ThemeSpec.default
101        spec.fontSize = 17
102        spec.light["heading-1"] = RGBA(hex: "#ff0000")
103        spec.dark["heading-1"] = RGBA(hex: "#ff0000")
104        spec.todo["WAIT"] = RGBA(hex: "#00ff00")
105        h.editor.themeSpec = spec
106        h.drainStyling()
107        let storage = h.textView.textStorage!
108        #expect((storage.attribute(.font, at: 11, effectiveRange: nil) as? NSFont)?.pointSize == 17)
109        let color = (storage.attribute(.foregroundColor, at: 3, effectiveRange: nil) as? NSColor)?.usingColorSpace(.sRGB)
110        #expect(color.map { ($0.redComponent * 255).rounded() } == 255)
111        #expect((storage.attribute(.font, at: 3, effectiveRange: nil) as? NSFont)?.pointSize == 20)
112    }
113}