krz/orgstar

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

Tests/OrgEditorAppKitTests/LineIndexTests.swift

322a87d47526d505d903e05d14e65a5464e1468f
orgstar/Tests/OrgEditorAppKitTests/LineIndexTests.swift history · blame · raw

52 lines · 2410 bytes

 1import Foundation
 2import Testing
 3import OrgPresentation
 4@testable import OrgEditorAppKit
 5
 6struct LineIndexTests {
 7    func naive(_ text: String) -> [Int] {
 8        var starts = [0]
 9        for (i, u) in text.utf16.enumerated() where u == 10 { starts.append(i + 1) }
10        return starts
11    }
12
13    @Test func followsRandomEdits() {
14        var generator = SystemRandomNumberGenerator()
15        let pieces = ["a", "bc\n", "\n", "\n\n", "xyz", "é\n", "😀", ""]
16        var text = "first\nsecond\n\nthird"
17        let index = LineIndex(text as NSString)
18        for _ in 0..<2000 {
19            let ns = text as NSString
20            let start = Int.random(in: 0...ns.length, using: &generator)
21            let end = min(ns.length, start + Int.random(in: 0...6, using: &generator))
22            let replacement = pieces.randomElement(using: &generator)!
23            text = ns.replacingCharacters(in: NSRange(location: start, length: end - start), with: replacement)
24            index.replace(start..<end, newLength: (replacement as NSString).length, in: text as NSString)
25            #expect(index.starts == naive(text))
26            if index.starts != naive(text) { return }
27        }
28        #expect(index.line(of: 0) == 1)
29        #expect(index.line(of: (text as NSString).length) == naive(text).count)
30    }
31}
32
33@MainActor
34struct ShadedBlockTests {
35    /// Bands after edits match a full search once typing settles.
36    @Test func incrementalMatchesFull() {
37        var generator = SystemRandomNumberGenerator()
38        let pieces = ["x", "word ", "\n", "#+begin_src sh\n", "#+end_src\n", ": fixed\n", "* H\n", "#+begin_quote\n", "#+end_quote\n", ""]
39        let h = Harness("* A\n#+begin_src sh\nls\n#+end_src\ntext\n: one\n* B\nbody\n")
40        for _ in 0..<400 {
41            let length = h.editor.document.text.utf16.count
42            let start = Int.random(in: 0...length, using: &generator)
43            let end = min(length, start + Int.random(in: 0...5, using: &generator))
44            let piece = pieces.randomElement(using: &generator)!
45            h.textView.insertText(piece, replacementRange: NSRange(location: start, length: end - start))
46            h.editor.settleBlocks()
47            let full = Presentation.shadedBlocks(h.editor.document.tree)
48            #expect(h.editor.shaded.all == full, "\(h.editor.document.text)")
49            if h.editor.shaded.all != full { return }
50        }
51    }
52}